#mesondefine GDK_WINDOWING_X11
#mesondefine GDK_WINDOWING_BROADWAY
+#mesondefine GDK_WINDOWING_MACOS
#mesondefine GDK_WINDOWING_WAYLAND
#mesondefine GDK_WINDOWING_WIN32
#include "broadway/gdkprivate-broadway.h"
#endif
+#ifdef GDK_WINDOWING_MACOS
+#include "macos/gdkmacosdisplay-private.h"
+#endif
+
#ifdef GDK_WINDOWING_WIN32
#include "win32/gdkwin32.h"
#include "win32/gdkprivate-win32.h"
#ifdef GDK_WINDOWING_QUARTZ
{ "quartz", _gdk_quartz_display_open },
#endif
+#ifdef GDK_WINDOWING_MACOS
+ { "macos", _gdk_macos_display_open },
+#endif
#ifdef GDK_WINDOWING_WIN32
{ "win32", _gdk_win32_display_open },
#endif
--- /dev/null
+/* GdkMacosBaseView.c
+ *
+ * Copyright 2005-2007 Imendio AB
+ * Copyright 2011 Hiroyuki Yamamoto
+ * Copyright 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#import "GdkMacosBaseView.h"
+#import "GdkMacosWindow.h"
+
+#include "gdkinternals.h"
+
+#include "gdkmacosdisplay-private.h"
+#include "gdkmacossurface-private.h"
+
+/* Text Input Client */
+#define TIC_MARKED_TEXT "tic-marked-text"
+#define TIC_SELECTED_POS "tic-selected-pos"
+#define TIC_SELECTED_LEN "tic-selected-len"
+#define TIC_INSERT_TEXT "tic-insert-text"
+#define TIC_IN_KEY_DOWN "tic-in-key-down"
+
+/* GtkIMContext */
+#define GIC_CURSOR_RECT "gic-cursor-rect"
+#define GIC_FILTER_KEY "gic-filter-key"
+#define GIC_FILTER_PASSTHRU 0
+#define GIC_FILTER_FILTERED 1
+
+@implementation GdkMacosBaseView
+
+-(id)initWithFrame:(NSRect)frameRect
+{
+ if ((self = [super initWithFrame: frameRect]))
+ {
+ NSRect rect = NSMakeRect (0, 0, 0, 0);
+ NSTrackingAreaOptions options;
+
+ markedRange = NSMakeRange (NSNotFound, 0);
+ selectedRange = NSMakeRange (0, 0);
+ [self setValue: @(YES) forKey: @"postsFrameChangedNotifications"];
+
+ options = (NSTrackingMouseEnteredAndExited |
+ NSTrackingMouseMoved |
+ NSTrackingInVisibleRect |
+ NSTrackingActiveAlways);
+ trackingArea = [[NSTrackingArea alloc] initWithRect:rect
+ options:options
+ owner:(id)self
+ userInfo:nil];
+ [self addTrackingArea:trackingArea];
+ }
+
+ return self;
+}
+
+-(void)setNeedsDisplay:(BOOL)needsDisplay
+{
+ for (id child in [self subviews])
+ [child setNeedsDisplay:needsDisplay];
+}
+
+-(void)setOpaqueRegion:(cairo_region_t *)region
+{
+ /* Do nothing */
+}
+
+-(BOOL)acceptsFirstMouse
+{
+ return YES;
+}
+
+-(BOOL)mouseDownCanMoveWindow
+{
+ return NO;
+}
+
+-(BOOL)acceptsFirstResponder
+{
+ GDK_NOTE (EVENTS, g_message ("acceptsFirstResponder"));
+ return YES;
+}
+
+-(BOOL)becomeFirstResponder
+{
+ GDK_NOTE (EVENTS, g_message ("becomeFirstResponder"));
+ return YES;
+}
+
+-(BOOL)resignFirstResponder
+{
+ GDK_NOTE (EVENTS, g_message ("resignFirstResponder"));
+ return YES;
+}
+
+-(void)setNeedsInvalidateShadow: (BOOL)invalidate
+{
+ needsInvalidateShadow = invalidate;
+}
+
+-(NSTrackingArea *)trackingArea
+{
+ return trackingArea;
+}
+
+-(GdkMacosSurface *)gdkSurface
+{
+ return [(GdkMacosWindow *)[self window] gdkSurface];
+}
+
+-(GdkMacosDisplay *)gdkDisplay
+{
+ GdkMacosSurface *surface = [self gdkSurface];
+ GdkDisplay *display = gdk_surface_get_display (GDK_SURFACE (surface));
+
+ return GDK_MACOS_DISPLAY (display);
+}
+
+-(void)keyDown:(NSEvent *)theEvent
+{
+ /* NOTE: When user press Cmd+A, interpretKeyEvents: will call noop:
+ * method. When user press and hold A to show the accented char window,
+ * it consumed repeating key down events for key 'A' do NOT call
+ * any other method. We use this behavior to determine if this key
+ * down event is filtered by interpretKeyEvents.
+ */
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_FILTERED));
+
+ GDK_NOTE (EVENTS, g_message ("keyDown"));
+ [self interpretKeyEvents: [NSArray arrayWithObject: theEvent]];
+}
+
+-(void)flagsChanged: (NSEvent *)theEvent
+{
+}
+
+-(NSUInteger)characterIndexForPoint:(NSPoint)aPoint
+{
+ GDK_NOTE (EVENTS, g_message ("characterIndexForPoint"));
+ return 0;
+}
+
+-(NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange: (NSRangePointer)actualRange
+{
+ GdkRectangle *rect;
+
+ GDK_NOTE (EVENTS, g_message ("firstRectForCharacterRange"));
+
+ if ((rect = g_object_get_data (G_OBJECT ([self gdkSurface]), GIC_CURSOR_RECT)))
+ {
+ GdkMacosDisplay *display = [self gdkDisplay];
+ int ns_x, ns_y;
+
+ _gdk_macos_display_to_display_coords (display,
+ rect->x, rect->y + rect->height,
+ &ns_x, &ns_y);
+
+ return NSMakeRect (ns_x, ns_y, rect->width, rect->height);
+ }
+
+ return NSMakeRect (0, 0, 0, 0);
+}
+
+-(NSArray *)validAttributesForMarkedText
+{
+ GDK_NOTE (EVENTS, g_message ("validAttributesForMarkedText"));
+ return [NSArray arrayWithObjects: NSUnderlineStyleAttributeName, nil];
+}
+
+-(NSAttributedString *)attributedSubstringForProposedRange: (NSRange)aRange actualRange: (NSRangePointer)actualRange
+{
+ GDK_NOTE (EVENTS, g_message ("attributedSubstringForProposedRange"));
+ return nil;
+}
+
+-(BOOL)hasMarkedText
+{
+ GDK_NOTE (EVENTS, g_message ("hasMarkedText"));
+ return markedRange.location != NSNotFound && markedRange.length != 0;
+}
+
+-(NSRange)markedRange
+{
+ GDK_NOTE (EVENTS, g_message ("markedRange"));
+ return markedRange;
+}
+
+-(NSRange)selectedRange
+{
+ GDK_NOTE (EVENTS, g_message ("selectedRange"));
+ return selectedRange;
+}
+
+-(void)unmarkText
+{
+ GDK_NOTE (EVENTS, g_message ("unmarkText"));
+
+ selectedRange = NSMakeRange (0, 0);
+ markedRange = NSMakeRange (NSNotFound, 0);
+
+ g_object_set_data_full (G_OBJECT ([self gdkSurface]), TIC_MARKED_TEXT, NULL, g_free);
+}
+
+-(void)setMarkedText:(id)aString selectedRange: (NSRange)newSelection replacementRange: (NSRange)replacementRange
+{
+ const char *str;
+
+ GDK_NOTE (EVENTS, g_message ("setMarkedText"));
+
+ if (replacementRange.location == NSNotFound)
+ {
+ markedRange = NSMakeRange (newSelection.location, [aString length]);
+ selectedRange = NSMakeRange (newSelection.location, newSelection.length);
+ }
+ else
+ {
+ markedRange = NSMakeRange (replacementRange.location, [aString length]);
+ selectedRange = NSMakeRange (replacementRange.location + newSelection.location, newSelection.length);
+ }
+
+ if ([aString isKindOfClass: [NSAttributedString class]])
+ str = [[aString string] UTF8String];
+ else
+ str = [aString UTF8String];
+
+ g_object_set_data_full (G_OBJECT ([self gdkSurface]), TIC_MARKED_TEXT, g_strdup (str), g_free);
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ TIC_SELECTED_POS,
+ GUINT_TO_POINTER (selectedRange.location));
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ TIC_SELECTED_LEN,
+ GUINT_TO_POINTER (selectedRange.length));
+
+ GDK_NOTE (EVENTS, g_message ("setMarkedText: set %s (%p, nsview %p): %s",
+ TIC_MARKED_TEXT, [self gdkSurface], self,
+ str ? str : "(empty)"));
+
+ /* handle text input changes by mouse events */
+ if (!GPOINTER_TO_UINT (g_object_get_data (G_OBJECT ([self gdkSurface]), TIC_IN_KEY_DOWN)))
+ _gdk_macos_surface_synthesize_null_key ([self gdkSurface]);
+}
+
+-(void)doCommandBySelector:(SEL)aSelector
+{
+ GDK_NOTE (EVENTS, g_message ("doCommandBySelector"));
+
+ if ([self respondsToSelector: aSelector])
+ [self performSelector: aSelector];
+}
+
+-(void)insertText:(id)aString replacementRange: (NSRange)replacementRange
+{
+ const char *str;
+ NSString *string;
+
+ GDK_NOTE (EVENTS, g_message ("insertText"));
+
+ if ([self hasMarkedText])
+ [self unmarkText];
+
+ if ([aString isKindOfClass: [NSAttributedString class]])
+ string = [aString string];
+ else
+ string = aString;
+
+ NSCharacterSet *ctrlChars = [NSCharacterSet controlCharacterSet];
+ NSCharacterSet *wsnlChars = [NSCharacterSet whitespaceAndNewlineCharacterSet];
+ if ([string rangeOfCharacterFromSet:ctrlChars].length &&
+ [string rangeOfCharacterFromSet:wsnlChars].length == 0)
+ {
+ /* discard invalid text input with Chinese input methods */
+ str = "";
+ [self unmarkText];
+ [[NSTextInputContext currentInputContext] discardMarkedText];
+ }
+ else
+ {
+ str = [string UTF8String];
+ }
+
+ g_object_set_data_full (G_OBJECT ([self gdkSurface]), TIC_INSERT_TEXT, g_strdup (str), g_free);
+ GDK_NOTE (EVENTS, g_message ("insertText: set %s (%p, nsview %p): %s",
+ TIC_INSERT_TEXT, [self gdkSurface], self,
+ str ? str : "(empty)"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_FILTERED));
+
+ /* handle text input changes by mouse events */
+ if (!GPOINTER_TO_UINT (g_object_get_data (G_OBJECT ([self gdkSurface]), TIC_IN_KEY_DOWN)))
+ _gdk_macos_surface_synthesize_null_key ([self gdkSurface]);
+}
+
+-(void)deleteBackward:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("deleteBackward"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)deleteForward:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("deleteForward"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)deleteToBeginningOfLine:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("deleteToBeginningOfLine"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)deleteToEndOfLine:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("deleteToEndOfLine"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)deleteWordBackward:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("deleteWordBackward"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)deleteWordForward:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("deleteWordForward"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)insertBacktab:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("insertBacktab"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)insertNewline:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("insertNewline"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)insertTab:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("insertTab"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveBackward:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("moveBackward"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveBackwardAndModifySelection:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("moveBackwardAndModifySelection"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveDown:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("moveDown"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveDownAndModifySelection:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("moveDownAndModifySelection"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveForward:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("moveForward"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveForwardAndModifySelection:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("moveForwardAndModifySelection"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveLeft:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("moveLeft"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveLeftAndModifySelection:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("moveLeftAndModifySelection"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveRight:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("moveRight"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveRightAndModifySelection:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("moveRightAndModifySelection"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveToBeginningOfDocument:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("moveToBeginningOfDocument"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveToBeginningOfDocumentAndModifySelection:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("moveToBeginningOfDocumentAndModifySelection"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveToBeginningOfLine:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("moveToBeginningOfLine"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveToBeginningOfLineAndModifySelection:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("moveToBeginningOfLineAndModifySelection"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveToEndOfDocument:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("moveToEndOfDocument"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveToEndOfDocumentAndModifySelection:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("moveToEndOfDocumentAndModifySelection"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveToEndOfLine:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("moveToEndOfLine"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveToEndOfLineAndModifySelection:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("moveToEndOfLineAndModifySelection"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveUp:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("moveUp"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveUpAndModifySelection:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("moveUpAndModifySelection"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveWordBackward:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("moveWordBackward"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveWordBackwardAndModifySelection:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("moveWordBackwardAndModifySelection"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveWordForward:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("moveWordForward"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveWordForwardAndModifySelection:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("moveWordForwardAndModifySelection"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveWordLeft:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("moveWordLeft"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveWordLeftAndModifySelection:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("moveWordLeftAndModifySelection"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveWordRight:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("moveWordRight"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)moveWordRightAndModifySelection:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("moveWordRightAndModifySelection"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)pageDown:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("pageDown"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)pageDownAndModifySelection:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("pageDownAndModifySelection"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)pageUp:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("pageUp"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)pageUpAndModifySelection:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("pageUpAndModifySelection"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)selectAll:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("selectAll"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)selectLine:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("selectLine"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)selectWord:(id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("selectWord"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+-(void)noop: (id)sender
+{
+ GDK_NOTE (EVENTS, g_message ("noop"));
+
+ g_object_set_data (G_OBJECT ([self gdkSurface]),
+ GIC_FILTER_KEY,
+ GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
+}
+
+@end
--- /dev/null
+/* GdkMacosBaseView.h
+ *
+ * Copyright © 2020 Red Hat, Inc.
+ * Copyright © 2005-2007 Imendio AB
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#import <AppKit/AppKit.h>
+#import <Foundation/Foundation.h>
+
+#include <gdk/gdk.h>
+
+#include "gdkmacosdisplay.h"
+#include "gdkmacossurface.h"
+
+#define GDK_IS_MACOS_BASE_VIEW(obj) ((obj) && [obj isKindOfClass:[GdkMacosBaseView class]])
+
+@interface GdkMacosBaseView : NSView <NSTextInputClient>
+{
+ NSTrackingArea *trackingArea;
+ BOOL needsInvalidateShadow;
+ NSRange markedRange;
+ NSRange selectedRange;
+}
+
+-(GdkMacosSurface *)gdkSurface;
+-(GdkMacosDisplay *)gdkDisplay;
+-(void)setNeedsInvalidateShadow: (BOOL)invalidate;
+-(NSTrackingArea *)trackingArea;
+-(void)setOpaqueRegion:(cairo_region_t *)region;
+
+@end
--- /dev/null
+/* GdkMacosCairoSubview.c
+ *
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#include <CoreGraphics/CoreGraphics.h>
+#include <cairo-quartz.h>
+
+#include "gdkinternals.h"
+
+#import "GdkMacosCairoSubview.h"
+#import "GdkMacosCairoView.h"
+
+#include "gdkmacossurface-private.h"
+
+@implementation GdkMacosCairoSubview
+
+-(BOOL)isOpaque
+{
+ return _isOpaque;
+}
+
+-(BOOL)isFlipped
+{
+ return YES;
+}
+
+-(GdkSurface *)gdkSurface
+{
+ return GDK_SURFACE ([(GdkMacosBaseView *)[self superview] gdkSurface]);
+}
+
+-(void)drawRect:(NSRect)rect
+{
+ CGContextRef cgContext;
+ GdkSurface *gdk_surface;
+ cairo_surface_t *dest;
+ const NSRect *rects = NULL;
+ NSView *root_view;
+ NSInteger n_rects = 0;
+ NSRect abs_bounds;
+ cairo_t *cr;
+ CGSize scale;
+ int scale_factor;
+
+ if (self->cairoSurface == NULL)
+ return;
+
+ /* Acquire everything we need to do translations, drawing, etc */
+ gdk_surface = [self gdkSurface];
+ scale_factor = gdk_surface_get_scale_factor (gdk_surface);
+ root_view = [[self window] contentView];
+ cgContext = [[NSGraphicsContext currentContext] CGContext];
+ abs_bounds = [self convertRect:[self bounds] toView:root_view];
+
+ CGContextSaveGState (cgContext);
+
+ /* Translate scaling to remove HiDPI scaling from CGContext as
+ * cairo will be doing that for us already.
+ */
+ scale = CGSizeMake (1.0, 1.0);
+ scale = CGContextConvertSizeToDeviceSpace (cgContext, scale);
+ CGContextScaleCTM (cgContext, 1.0 / scale.width, 1.0 / scale.height);
+
+ /* Create the cairo surface to draw to the CGContext and translate
+ * coordinates so we can pretend we are in the same coordinate system
+ * as the GDK surface.
+ */
+ dest = cairo_quartz_surface_create_for_cg_context (cgContext,
+ gdk_surface->width * scale_factor,
+ gdk_surface->height * scale_factor);
+ cairo_surface_set_device_scale (dest, scale_factor, scale_factor);
+
+ /* Create cairo context and translate things into the origin of
+ * the topmost contentView so that we just draw at 0,0 with a
+ * clip region to paint the surface.
+ */
+ cr = cairo_create (dest);
+ cairo_translate (cr, -abs_bounds.origin.x, -abs_bounds.origin.y);
+
+ /* Clip the cairo context based on the rectangles to be drawn
+ * within the bounding box :rect.
+ */
+ [self getRectsBeingDrawn:&rects count:&n_rects];
+ for (NSInteger i = 0; i < n_rects; i++)
+ {
+ NSRect area = [self convertRect:rects[i] toView:root_view];
+ cairo_rectangle (cr,
+ area.origin.x, area.origin.y,
+ area.size.width, area.size.height);
+ }
+ cairo_clip (cr);
+
+ /* Now paint the surface (without blending) as we do not need
+ * any compositing here. The transparent regions (like shadows)
+ * are already on non-opaque layers.
+ */
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_set_source_surface (cr, self->cairoSurface, 0, 0);
+ cairo_paint (cr);
+
+ /* Cleanup state, flush the surface to the backing layer, and
+ * restore GState for future use.
+ */
+ cairo_destroy (cr);
+ cairo_surface_flush (dest);
+ cairo_surface_destroy (dest);
+ CGContextRestoreGState (cgContext);
+}
+
+-(void)setCairoSurface:(cairo_surface_t *)surface
+ withDamage:(cairo_region_t *)region
+{
+ if (surface != self->cairoSurface)
+ {
+ g_clear_pointer (&self->cairoSurface, cairo_surface_destroy);
+ if (surface != NULL)
+ self->cairoSurface = cairo_surface_reference (surface);
+ }
+
+ if (region != NULL)
+ {
+ NSView *root_view = [[self window] contentView];
+ NSRect abs_bounds = [self convertRect:[self bounds] toView:root_view];
+ guint n_rects = cairo_region_num_rectangles (region);
+
+ for (guint i = 0; i < n_rects; i++)
+ {
+ cairo_rectangle_int_t rect;
+ NSRect nsrect;
+
+ cairo_region_get_rectangle (region, i, &rect);
+ nsrect = NSMakeRect (rect.x, rect.y, rect.width, rect.height);
+
+ if (NSIntersectsRect (abs_bounds, nsrect))
+ {
+ nsrect.origin.x -= abs_bounds.origin.x;
+ nsrect.origin.y -= abs_bounds.origin.y;
+ [self setNeedsDisplayInRect:nsrect];
+ }
+ }
+ }
+
+ for (id view in [self subviews])
+ [(GdkMacosCairoSubview *)view setCairoSurface:surface
+ withDamage:region];
+}
+
+-(void)setOpaque:(BOOL)opaque
+{
+ self->_isOpaque = opaque;
+}
+
+@end
--- /dev/null
+/* GdkMacosCairoSubview.h
+ *
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include <AppKit/AppKit.h>
+
+#define GDK_IS_MACOS_CAIRO_SUBVIEW(obj) ((obj) && [obj isKindOfClass:[GdkMacosCairoSubview class]])
+
+@interface GdkMacosCairoSubview : NSView
+{
+ BOOL _isOpaque;
+ cairo_surface_t *cairoSurface;
+}
+
+-(void)setOpaque:(BOOL)opaque;
+-(void)setCairoSurface:(cairo_surface_t *)cairoSurface
+ withDamage:(cairo_region_t *)region;
+
+@end
--- /dev/null
+/* GdkMacosCairoView.c
+ *
+ * Copyright © 2020 Red Hat, Inc.
+ * Copyright © 2005-2007 Imendio AB
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#include <CoreGraphics/CoreGraphics.h>
+#include <cairo-quartz.h>
+
+#include "gdkinternals.h"
+
+#import "GdkMacosCairoView.h"
+#import "GdkMacosCairoSubview.h"
+
+#include "gdkmacossurface-private.h"
+
+@implementation GdkMacosCairoView
+
+-(void)dealloc
+{
+ g_clear_pointer (&self->opaque, g_ptr_array_unref);
+ self->transparent = NULL;
+
+ [super dealloc];
+}
+
+-(BOOL)isOpaque
+{
+ if ([self window])
+ return [[self window] isOpaque];
+ return YES;
+}
+
+-(BOOL)isFlipped
+{
+ return YES;
+}
+
+-(void)setCairoSurface:(cairo_surface_t *)cairoSurface
+ withDamage:(cairo_region_t *)cairoRegion
+{
+ for (id view in [self subviews])
+ [(GdkMacosCairoSubview *)view setCairoSurface:cairoSurface
+ withDamage:cairoRegion];
+}
+
+-(void)removeOpaqueChildren
+{
+ [[self->transparent subviews]
+ makeObjectsPerformSelector:@selector(removeFromSuperview)];
+
+ if (self->opaque->len)
+ g_ptr_array_remove_range (self->opaque, 0, self->opaque->len);
+}
+
+-(void)setOpaqueRegion:(cairo_region_t *)region
+{
+ NSRect abs_bounds;
+ guint n_rects;
+
+ if (region == NULL)
+ return;
+
+ abs_bounds = [self convertRect:[self bounds] toView:nil];
+ n_rects = cairo_region_num_rectangles (region);
+
+ /* The common case (at least for opaque windows and CSD) is that we will
+ * have either one or two opaque rectangles. If we detect that the same
+ * number of them are available as the previous, we can just resize the
+ * previous ones to avoid adding/removing views at a fast rate while
+ * resizing.
+ */
+ if (n_rects == self->opaque->len)
+ {
+ for (guint i = 0; i < n_rects; i++)
+ {
+ GdkMacosCairoSubview *child;
+ cairo_rectangle_int_t rect;
+
+ child = g_ptr_array_index (self->opaque, i);
+ cairo_region_get_rectangle (region, i, &rect);
+
+ [child setFrame:NSMakeRect (rect.x - abs_bounds.origin.x,
+ rect.y - abs_bounds.origin.y,
+ rect.width,
+ rect.height)];
+ }
+
+ return;
+ }
+
+ [self removeOpaqueChildren];
+ for (guint i = 0; i < n_rects; i++)
+ {
+ GdkMacosCairoSubview *child;
+ cairo_rectangle_int_t rect;
+ NSRect nsrect;
+
+ cairo_region_get_rectangle (region, i, &rect);
+ nsrect = NSMakeRect (rect.x - abs_bounds.origin.x,
+ rect.y - abs_bounds.origin.y,
+ rect.width,
+ rect.height);
+
+ child = [[GdkMacosCairoSubview alloc] initWithFrame:nsrect];
+ [child setOpaque:YES];
+ [child setWantsLayer:YES];
+ [self->transparent addSubview:child];
+ g_ptr_array_add (self->opaque, child);
+ }
+}
+
+-(NSView *)initWithFrame:(NSRect)frame
+{
+ if ((self = [super initWithFrame:frame]))
+ {
+ /* An array to track all the opaque children placed into
+ * the child self->transparent. This allows us to reuse them
+ * when we receive a new opaque area instead of discarding
+ * them on each draw.
+ */
+ self->opaque = g_ptr_array_new ();
+
+ /* Setup our primary subview which will render all content that is not
+ * within an opaque region (such as shadows for CSD windows). For opaque
+ * windows, this will all be obscurred by other views, so it doesn't
+ * matter much to have it here.
+ */
+ self->transparent = [[GdkMacosCairoSubview alloc] initWithFrame:frame];
+ [self addSubview:self->transparent];
+
+ }
+
+ return self;
+}
+
+-(void)setFrame:(NSRect)rect
+{
+ [super setFrame:rect];
+ [self->transparent setFrame:NSMakeRect (0, 0, rect.size.width, rect.size.height)];
+}
+
+-(BOOL)acceptsFirstMouse
+{
+ return YES;
+}
+
+-(BOOL)mouseDownCanMoveWindow
+{
+ return NO;
+}
+
+@end
--- /dev/null
+/* GdkMacosCairoView.h
+ *
+ * Copyright © 2020 Red Hat, Inc.
+ * Copyright © 2005-2007 Imendio AB
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include <cairo.h>
+
+#import "GdkMacosBaseView.h"
+
+#define GDK_IS_MACOS_CAIRO_VIEW(obj) ((obj) && [obj isKindOfClass:[GdkMacosCairoView class]])
+
+@interface GdkMacosCairoView : GdkMacosBaseView
+{
+ NSView *transparent;
+ GPtrArray *opaque;
+}
+
+-(void)setCairoSurface:(cairo_surface_t *)cairoSurface
+ withDamage:(cairo_region_t *)region;
+
+@end
--- /dev/null
+/* GdkMacosGLLayer.c
+ *
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+/* Based on Chromium image_transport_surface_calayer_mac.mm
+ * See the BSD-style license above.
+ */
+
+#include "config.h"
+
+#include <OpenGL/gl.h>
+
+#import "GdkMacosGLLayer.h"
+
+@implementation GdkMacosGLLayer
+
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+
+-(id)initWithContext:(NSOpenGLContext *)shared
+{
+ [super init];
+ _shared = [shared retain];
+ return self;
+}
+
+-(void)dealloc
+{
+ [_shared release];
+ _shared = nil;
+
+ [super dealloc];
+}
+
+-(void)setContentsRect:(NSRect)bounds
+{
+ _pixelSize = bounds.size;
+ [super setContentsRect:bounds];
+}
+
+-(CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask
+{
+ return CGLRetainPixelFormat ([[_shared pixelFormat] CGLPixelFormatObj]);
+}
+
+-(CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat
+{
+ CGLContextObj context = NULL;
+ CGLCreateContext (pixelFormat, [_shared CGLContextObj], &context);
+ return context;
+}
+
+-(BOOL)canDrawInCGLContext:(CGLContextObj)glContext
+ pixelFormat:(CGLPixelFormatObj)pixelFormat
+ forLayerTime:(CFTimeInterval)timeInterval
+ displayTime:(const CVTimeStamp*)timeStamp
+{
+ return YES;
+}
+
+-(void)drawInCGLContext:(CGLContextObj)glContext
+ pixelFormat:(CGLPixelFormatObj)pixelFormat
+ forLayerTime:(CFTimeInterval)timeInterval
+ displayTime:(const CVTimeStamp*)timeStamp
+{
+ if (_texture == 0)
+ return;
+
+ glClearColor (1, 0, 1, 1);
+ glClear (GL_COLOR_BUFFER_BIT);
+ GLint viewport[4] = {0, 0, 0, 0};
+ glGetIntegerv (GL_VIEWPORT, viewport);
+ NSSize viewportSize = NSMakeSize (viewport[2], viewport[3]);
+
+ /* Set the coordinate system to be one-to-one with pixels. */
+ glMatrixMode (GL_PROJECTION);
+ glLoadIdentity ();
+ glOrtho (0, viewportSize.width, 0, viewportSize.height, -1, 1);
+ glMatrixMode (GL_MODELVIEW);
+ glLoadIdentity ();
+
+ /* Draw a fullscreen quad. */
+ glColor4f (1, 1, 1, 1);
+ glEnable (GL_TEXTURE_RECTANGLE_ARB);
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, _texture);
+ glBegin (GL_QUADS);
+ {
+ glTexCoord2f (0, 0);
+ glVertex2f (0, 0);
+ glTexCoord2f (0, _pixelSize.height);
+ glVertex2f (0, _pixelSize.height);
+ glTexCoord2f (_pixelSize.width, _pixelSize.height);
+ glVertex2f (_pixelSize.width, _pixelSize.height);
+ glTexCoord2f (_pixelSize.width, 0);
+ glVertex2f (_pixelSize.width, 0);
+ }
+ glEnd ();
+ glBindTexture (0, _texture);
+ glDisable (GL_TEXTURE_RECTANGLE_ARB);
+ [super drawInCGLContext:glContext
+ pixelFormat:pixelFormat
+ forLayerTime:timeInterval
+ displayTime:timeStamp];
+}
+
+-(void)setTexture:(GLuint)texture
+{
+ _texture = texture;
+ [self setNeedsDisplay];
+}
+
+G_GNUC_END_IGNORE_DEPRECATIONS
+
+@end
--- /dev/null
+/* GdkMacosGLLayer.h
+ *
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include <AppKit/AppKit.h>
+#include <glib.h>
+
+#define GDK_IS_MACOS_GL_LAYER(obj) ((obj) && [obj isKindOfClass:[GdkMacosGLLayer class]])
+
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+
+@interface GdkMacosGLLayer : CAOpenGLLayer
+{
+ NSOpenGLContext *_shared;
+ GLuint _texture;
+ NSSize _pixelSize;
+}
+
+-(id)initWithContext:(NSOpenGLContext *)shared;
+-(void)setTexture:(GLuint)texture;
+
+@end
+
+G_GNUC_END_IGNORE_DEPRECATIONS
--- /dev/null
+/* GdkMacosWindow.m
+ *
+ * Copyright © 2020 Red Hat, Inc.
+ * Copyright © 2005-2007 Imendio AB
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#include <gdk/gdk.h>
+
+#import "GdkMacosBaseView.h"
+#import "GdkMacosCairoView.h"
+#import "GdkMacosWindow.h"
+
+#include "gdkmacosdisplay-private.h"
+#include "gdkmacossurface-private.h"
+#include "gdkmacospopupsurface-private.h"
+#include "gdkmacostoplevelsurface-private.h"
+
+#include "gdkmonitorprivate.h"
+#include "gdksurfaceprivate.h"
+
+@implementation GdkMacosWindow
+
+-(BOOL)windowShouldClose:(id)sender
+{
+ GdkDisplay *display;
+ GdkEvent *event;
+ GList *node;
+
+ display = gdk_surface_get_display (GDK_SURFACE (gdk_surface));
+ event = gdk_delete_event_new (GDK_SURFACE (gdk_surface));
+ node = _gdk_event_queue_append (display, event);
+ _gdk_windowing_got_event (display, node, event,
+ _gdk_display_get_next_serial (display));
+
+ return NO;
+}
+
+-(void)windowWillMiniaturize:(NSNotification *)aNotification
+{
+ if (GDK_IS_MACOS_TOPLEVEL_SURFACE (gdk_surface))
+ _gdk_macos_toplevel_surface_detach_from_parent (GDK_MACOS_TOPLEVEL_SURFACE (gdk_surface));
+ else if (GDK_IS_MACOS_POPUP_SURFACE (gdk_surface))
+ _gdk_macos_popup_surface_detach_from_parent (GDK_MACOS_POPUP_SURFACE (gdk_surface));
+}
+
+-(void)windowDidMiniaturize:(NSNotification *)aNotification
+{
+ gdk_synthesize_surface_state (GDK_SURFACE (gdk_surface), 0, GDK_SURFACE_STATE_MINIMIZED);
+}
+
+-(void)windowDidDeminiaturize:(NSNotification *)aNotification
+{
+ if (GDK_IS_MACOS_TOPLEVEL_SURFACE (gdk_surface))
+ _gdk_macos_toplevel_surface_attach_to_parent (GDK_MACOS_TOPLEVEL_SURFACE (gdk_surface));
+ else if (GDK_IS_MACOS_POPUP_SURFACE (gdk_surface))
+ _gdk_macos_popup_surface_attach_to_parent (GDK_MACOS_POPUP_SURFACE (gdk_surface));
+
+ gdk_synthesize_surface_state (GDK_SURFACE (gdk_surface), GDK_SURFACE_STATE_MINIMIZED, 0);
+}
+
+-(void)windowDidBecomeKey:(NSNotification *)aNotification
+{
+ gdk_synthesize_surface_state (GDK_SURFACE (gdk_surface), 0, GDK_SURFACE_STATE_FOCUSED);
+ _gdk_macos_display_surface_became_key ([self gdkDisplay], gdk_surface);
+}
+
+-(void)windowDidResignKey:(NSNotification *)aNotification
+{
+ gdk_synthesize_surface_state (GDK_SURFACE (gdk_surface), GDK_SURFACE_STATE_FOCUSED, 0);
+ _gdk_macos_display_surface_resigned_key ([self gdkDisplay], gdk_surface);
+}
+
+-(void)windowDidBecomeMain:(NSNotification *)aNotification
+{
+ if (![self isVisible])
+ {
+ /* Note: This is a hack needed because for unknown reasons, hidden
+ * windows get shown when clicking the dock icon when the application
+ * is not already active.
+ */
+ [self orderOut:nil];
+ return;
+ }
+
+ _gdk_macos_display_surface_became_main ([self gdkDisplay], gdk_surface);
+}
+
+-(void)windowDidResignMain:(NSNotification *)aNotification
+{
+ _gdk_macos_display_surface_resigned_main ([self gdkDisplay], gdk_surface);
+}
+
+/* Used in combination with NSLeftMouseUp in sendEvent to keep track
+ * of when the window is being moved with the mouse.
+ */
+-(void)windowWillMove:(NSNotification *)aNotification
+{
+ inMove = YES;
+}
+
+-(void)sendEvent:(NSEvent *)event
+{
+ NSEventType event_type = [event type];
+
+ switch ((int)event_type)
+ {
+ case NSEventTypeLeftMouseUp: {
+ GdkDisplay *display = gdk_surface_get_display (GDK_SURFACE (gdk_surface));
+ double time = ((double)[event timestamp]) * 1000.0;
+
+ _gdk_macos_display_break_all_grabs (GDK_MACOS_DISPLAY (display), time);
+
+ inManualMove = NO;
+ inManualResize = NO;
+ inMove = NO;
+
+ /* We need to deliver the event to the proper drag gestures or we
+ * will leave the window in inconsistent state that requires clicking
+ * in the window to cancel the gesture.
+ *
+ * TODO: Can we improve grab breaking to fix this?
+ */
+ _gdk_macos_display_send_button_event ([self gdkDisplay], event);
+
+ break;
+ }
+
+ case NSEventTypeLeftMouseDragged:
+ if ([self trackManualMove] || [self trackManualResize])
+ return;
+ break;
+
+ default:
+ break;
+ }
+
+ [super sendEvent:event];
+}
+
+-(BOOL)isInMove
+{
+ return inMove;
+}
+
+-(void)checkSendEnterNotify
+{
+ /* When a new window has been created, and the mouse is in the window
+ * area, we will not receive an NSEventTypeMouseEntered event.
+ * Therefore, we synthesize an enter notify event manually.
+ */
+ if (!initialPositionKnown)
+ {
+ initialPositionKnown = YES;
+
+ if (NSPointInRect ([NSEvent mouseLocation], [self frame]))
+ {
+ GdkMacosBaseView *view = (GdkMacosBaseView *)[self contentView];
+ NSEvent *event;
+
+ event = [NSEvent enterExitEventWithType: NSEventTypeMouseEntered
+ location: [self mouseLocationOutsideOfEventStream]
+ modifierFlags: 0
+ timestamp: [[NSApp currentEvent] timestamp]
+ windowNumber: [self windowNumber]
+ context: NULL
+ eventNumber: 0
+ trackingNumber: (NSInteger)[view trackingArea]
+ userData: nil];
+
+ [NSApp postEvent:event atStart:NO];
+ }
+ }
+}
+
+-(void)windowDidUnmaximize
+{
+ NSWindowStyleMask style_mask = [self styleMask];
+
+ gdk_synthesize_surface_state (GDK_SURFACE (gdk_surface), GDK_SURFACE_STATE_MAXIMIZED, 0);
+
+ /* If we are using CSD, then we transitioned to an opaque
+ * window while we were maximized. Now we need to drop that
+ * as we are leaving maximized state.
+ */
+ if ((style_mask & NSWindowStyleMaskTitled) == 0 && [self isOpaque])
+ [self setOpaque:NO];
+}
+
+-(void)windowDidMove:(NSNotification *)aNotification
+{
+ GdkSurface *surface = GDK_SURFACE (gdk_surface);
+ gboolean maximized = (surface->state & GDK_SURFACE_STATE_MAXIMIZED) != 0;
+
+ /* In case the window is changed when maximized remove the maximized state */
+ if (maximized && !inMaximizeTransition && !NSEqualRects (lastMaximizedFrame, [self frame]))
+ [self windowDidUnmaximize];
+
+ _gdk_macos_surface_update_position (gdk_surface);
+ _gdk_macos_surface_reposition_children (gdk_surface);
+
+ [self checkSendEnterNotify];
+}
+
+-(void)windowDidResize:(NSNotification *)aNotification
+{
+ NSRect content_rect;
+ GdkSurface *surface;
+ GdkDisplay *display;
+ GdkEvent *event;
+ gboolean maximized;
+ GList *node;
+
+ surface = GDK_SURFACE (gdk_surface);
+ display = gdk_surface_get_display (surface);
+
+ content_rect = [self contentRectForFrameRect:[self frame]];
+ maximized = (surface->state & GDK_SURFACE_STATE_MAXIMIZED) != 0;
+
+ /* see same in windowDidMove */
+ if (maximized && !inMaximizeTransition && !NSEqualRects (lastMaximizedFrame, [self frame]))
+ [self windowDidUnmaximize];
+
+ surface->width = content_rect.size.width;
+ surface->height = content_rect.size.height;
+
+ /* Certain resize operations (e.g. going fullscreen), also move the
+ * origin of the window.
+ */
+ _gdk_macos_surface_update_position (GDK_MACOS_SURFACE (surface));
+
+ [[self contentView] setFrame:NSMakeRect (0, 0, surface->width, surface->height)];
+
+ _gdk_surface_update_size (surface);
+
+ /* Synthesize a configure event */
+ event = gdk_configure_event_new (surface,
+ content_rect.size.width,
+ content_rect.size.height);
+ node = _gdk_event_queue_append (display, event);
+ _gdk_windowing_got_event (display, node, event,
+ _gdk_display_get_next_serial (display));
+
+ _gdk_macos_surface_reposition_children (gdk_surface);
+
+ [self checkSendEnterNotify];
+}
+
+-(id)initWithContentRect:(NSRect)contentRect
+ styleMask:(NSWindowStyleMask)styleMask
+ backing:(NSBackingStoreType)backingType
+ defer:(BOOL)flag
+ screen:(NSScreen *)screen
+{
+ GdkMacosCairoView *view;
+
+ self = [super initWithContentRect:contentRect
+ styleMask:styleMask
+ backing:backingType
+ defer:flag
+ screen:screen];
+
+ [self setAcceptsMouseMovedEvents:YES];
+ [self setDelegate:(id<NSWindowDelegate>)self];
+ [self setReleasedWhenClosed:YES];
+
+ view = [[GdkMacosCairoView alloc] initWithFrame:contentRect];
+ [self setContentView:view];
+ [view release];
+
+ return self;
+}
+
+-(BOOL)canBecomeMainWindow
+{
+ return GDK_IS_TOPLEVEL (gdk_surface);
+}
+
+-(BOOL)canBecomeKeyWindow
+{
+ return GDK_IS_TOPLEVEL (gdk_surface);
+}
+
+-(void)showAndMakeKey:(BOOL)makeKey
+{
+ inShowOrHide = YES;
+
+ if (makeKey && [self canBecomeKeyWindow])
+ [self makeKeyAndOrderFront:nil];
+ else
+ [self orderFront:nil];
+
+ inShowOrHide = NO;
+
+ [self checkSendEnterNotify];
+}
+
+-(void)hide
+{
+ inShowOrHide = YES;
+ [self orderOut:nil];
+ inShowOrHide = NO;
+
+ initialPositionKnown = NO;
+}
+
+-(BOOL)trackManualMove
+{
+ NSRect windowFrame;
+ NSPoint currentLocation;
+ GdkMonitor *monitor;
+ GdkRectangle geometry;
+ GdkRectangle workarea;
+ int shadow_top = 0;
+ int shadow_left = 0;
+ int shadow_right = 0;
+ int shadow_bottom = 0;
+ GdkRectangle window_gdk;
+ GdkPoint pointer_position;
+ GdkPoint new_origin;
+
+ if (!inManualMove)
+ return NO;
+
+ /* Get our shadow so we can adjust the window position sans-shadow */
+ _gdk_macos_surface_get_shadow (gdk_surface,
+ &shadow_top,
+ &shadow_right,
+ &shadow_bottom,
+ &shadow_left);
+
+ windowFrame = [self frame];
+ currentLocation = [NSEvent mouseLocation];
+
+ /* Update the snapping geometry to match the current monitor */
+ monitor = _gdk_macos_display_get_monitor_at_display_coords ([self gdkDisplay],
+ currentLocation.x,
+ currentLocation.y);
+ gdk_monitor_get_geometry (monitor, &geometry);
+ gdk_monitor_get_workarea (monitor, &workarea);
+ _edge_snapping_set_monitor (&self->snapping, &geometry, &workarea);
+
+ /* Convert origins to GDK coordinates */
+ _gdk_macos_display_from_display_coords ([self gdkDisplay],
+ currentLocation.x,
+ currentLocation.y,
+ &pointer_position.x,
+ &pointer_position.y);
+ _gdk_macos_display_from_display_coords ([self gdkDisplay],
+ windowFrame.origin.x,
+ windowFrame.origin.y + windowFrame.size.height,
+ &window_gdk.x,
+ &window_gdk.y);
+ window_gdk.width = windowFrame.size.width;
+ window_gdk.height = windowFrame.size.height;
+
+ /* Subtract our shadowin from the window */
+ window_gdk.x += shadow_left;
+ window_gdk.y += shadow_top;
+ window_gdk.width = window_gdk.width - shadow_left - shadow_right;
+ window_gdk.height = window_gdk.height - shadow_top - shadow_bottom;
+
+ /* Now place things on the monitor */
+ _edge_snapping_motion (&self->snapping, &pointer_position, &window_gdk);
+
+ /* And add our shadow back to the frame */
+ window_gdk.x -= shadow_left;
+ window_gdk.y -= shadow_top;
+ window_gdk.width += shadow_left + shadow_right;
+ window_gdk.height += shadow_top + shadow_bottom;
+
+ /* Convert to quartz coordiantes */
+ _gdk_macos_display_to_display_coords ([self gdkDisplay],
+ window_gdk.x,
+ window_gdk.y + window_gdk.height,
+ &new_origin.x, &new_origin.y);
+ windowFrame.origin.x = new_origin.x;
+ windowFrame.origin.y = new_origin.y;
+
+ /* And now apply the frame to the window */
+ [self setFrameOrigin:NSMakePoint(new_origin.x, new_origin.y)];
+
+ return YES;
+}
+
+/* Used by gdkmacosdisplay-translate.c to decide if our sendEvent() handler
+ * above will see the event or if it will be subjected to standard processing
+ * by GDK.
+*/
+-(BOOL)isInManualResizeOrMove
+{
+ return inManualResize || inManualMove;
+}
+
+-(void)beginManualMove
+{
+ NSPoint initialMoveLocation;
+ GdkPoint point;
+ GdkMonitor *monitor;
+ GdkRectangle geometry;
+ GdkRectangle area;
+ GdkRectangle workarea;
+
+ if (inMove || inManualMove || inManualResize)
+ return;
+
+ inManualMove = YES;
+
+ monitor = _gdk_macos_surface_get_best_monitor ([self gdkSurface]);
+ gdk_monitor_get_geometry (monitor, &geometry);
+ gdk_monitor_get_workarea (monitor, &workarea);
+
+ initialMoveLocation = [NSEvent mouseLocation];
+
+ _gdk_macos_display_from_display_coords ([self gdkDisplay],
+ initialMoveLocation.x,
+ initialMoveLocation.y,
+ &point.x,
+ &point.y);
+
+ area.x = gdk_surface->root_x;
+ area.y = gdk_surface->root_y;
+ area.width = GDK_SURFACE (gdk_surface)->width;
+ area.height = GDK_SURFACE (gdk_surface)->height;
+
+ _edge_snapping_init (&self->snapping,
+ &geometry,
+ &workarea,
+ &point,
+ &area);
+}
+
+-(BOOL)trackManualResize
+{
+ NSPoint mouse_location;
+ NSRect new_frame;
+ float mdx, mdy, dw, dh, dx, dy;
+ NSSize min_size;
+
+ if (!inManualResize || inTrackManualResize)
+ return NO;
+
+ inTrackManualResize = YES;
+
+ mouse_location = [self convertPointToScreen:[self mouseLocationOutsideOfEventStream]];
+ mdx = initialResizeLocation.x - mouse_location.x;
+ mdy = initialResizeLocation.y - mouse_location.y;
+
+ /* Set how a mouse location delta translates to changes in width,
+ * height and position.
+ */
+ dw = dh = dx = dy = 0.0;
+ if (resizeEdge == GDK_SURFACE_EDGE_EAST ||
+ resizeEdge == GDK_SURFACE_EDGE_NORTH_EAST ||
+ resizeEdge == GDK_SURFACE_EDGE_SOUTH_EAST)
+ {
+ dw = -1.0;
+ }
+ if (resizeEdge == GDK_SURFACE_EDGE_NORTH ||
+ resizeEdge == GDK_SURFACE_EDGE_NORTH_WEST ||
+ resizeEdge == GDK_SURFACE_EDGE_NORTH_EAST)
+ {
+ dh = -1.0;
+ }
+ if (resizeEdge == GDK_SURFACE_EDGE_SOUTH ||
+ resizeEdge == GDK_SURFACE_EDGE_SOUTH_WEST ||
+ resizeEdge == GDK_SURFACE_EDGE_SOUTH_EAST)
+ {
+ dh = 1.0;
+ dy = -1.0;
+ }
+ if (resizeEdge == GDK_SURFACE_EDGE_WEST ||
+ resizeEdge == GDK_SURFACE_EDGE_NORTH_WEST ||
+ resizeEdge == GDK_SURFACE_EDGE_SOUTH_WEST)
+ {
+ dw = 1.0;
+ dx = -1.0;
+ }
+
+ /* Apply changes to the frame captured when we started resizing */
+ new_frame = initialResizeFrame;
+ new_frame.origin.x += mdx * dx;
+ new_frame.origin.y += mdy * dy;
+ new_frame.size.width += mdx * dw;
+ new_frame.size.height += mdy * dh;
+
+ /* In case the resulting window would be too small reduce the
+ * change to both size and position.
+ */
+ min_size = [self contentMinSize];
+
+ if (new_frame.size.width < min_size.width)
+ {
+ if (dx)
+ new_frame.origin.x -= min_size.width - new_frame.size.width;
+ new_frame.size.width = min_size.width;
+ }
+
+ if (new_frame.size.height < min_size.height)
+ {
+ if (dy)
+ new_frame.origin.y -= min_size.height - new_frame.size.height;
+ new_frame.size.height = min_size.height;
+ }
+
+ /* We could also apply aspect ratio:
+ new_frame.size.height = new_frame.size.width / [self aspectRatio].width * [self aspectRatio].height;
+ */
+
+ [self setFrame:new_frame display:YES];
+
+ /* Let the resizing be handled by GTK+. */
+ if (g_main_context_pending (NULL))
+ g_main_context_iteration (NULL, FALSE);
+
+ inTrackManualResize = NO;
+
+ return YES;
+}
+
+-(void)beginManualResize:(GdkSurfaceEdge)edge
+{
+ if (inMove || inManualMove || inManualResize)
+ return;
+
+ inManualResize = YES;
+ resizeEdge = edge;
+
+ initialResizeFrame = [self frame];
+ initialResizeLocation = [self convertPointToScreen:[self mouseLocationOutsideOfEventStream]];
+}
+
+-(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
+{
+ return NSDragOperationNone;
+}
+
+-(void)draggingEnded:(id <NSDraggingInfo>)sender
+{
+}
+
+-(void)draggingExited:(id <NSDraggingInfo>)sender
+{
+}
+
+-(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
+{
+ return NSDragOperationNone;
+}
+
+-(BOOL)performDragOperation:(id <NSDraggingInfo>)sender
+{
+ return YES;
+}
+
+-(BOOL)wantsPeriodicDraggingUpdates
+{
+ return NO;
+}
+
+-(void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation
+{
+}
+
+-(void)setStyleMask:(NSWindowStyleMask)styleMask
+{
+ gboolean was_fullscreen;
+ gboolean is_fullscreen;
+ gboolean was_opaque;
+ gboolean is_opaque;
+
+ was_fullscreen = (([self styleMask] & NSWindowStyleMaskFullScreen) != 0);
+ was_opaque = (([self styleMask] & NSWindowStyleMaskTitled) != 0);
+
+ [super setStyleMask:styleMask];
+
+ is_fullscreen = (([self styleMask] & NSWindowStyleMaskFullScreen) != 0);
+ is_opaque = (([self styleMask] & NSWindowStyleMaskTitled) != 0);
+
+ if (was_fullscreen != is_fullscreen)
+ _gdk_macos_surface_update_fullscreen_state (gdk_surface);
+
+ if (was_opaque != is_opaque)
+ {
+ [self setOpaque:is_opaque];
+
+ if (!is_opaque)
+ [self setBackgroundColor:[NSColor clearColor]];
+ }
+}
+
+-(NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
+{
+ GdkMacosSurface *surface = gdk_surface;
+ NSRect rect;
+ gint shadow_top;
+
+ /* Allow the window to move up "shadow_top" more than normally allowed
+ * by the default impl. This makes it possible to move windows with
+ * client side shadow right up to the screen's menu bar. */
+ _gdk_macos_surface_get_shadow (surface, &shadow_top, NULL, NULL, NULL);
+ rect = [super constrainFrameRect:frameRect toScreen:screen];
+ if (frameRect.origin.y > rect.origin.y)
+ rect.origin.y = MIN (frameRect.origin.y, rect.origin.y + shadow_top);
+
+ return rect;
+}
+
+-(NSRect)windowWillUseStandardFrame:(NSWindow *)nsWindow
+ defaultFrame:(NSRect)newFrame
+{
+ NSRect screenFrame = [[self screen] visibleFrame];
+ GdkMacosSurface *surface = gdk_surface;
+ gboolean maximized = GDK_SURFACE (surface)->state & GDK_SURFACE_STATE_MAXIMIZED;
+
+ if (!maximized)
+ return screenFrame;
+ else
+ return lastUnmaximizedFrame;
+}
+
+-(BOOL)windowShouldZoom:(NSWindow *)nsWindow
+ toFrame:(NSRect)newFrame
+{
+ GdkMacosSurface *surface = gdk_surface;
+ GdkSurfaceState state = GDK_SURFACE (surface)->state;
+
+ if (state & GDK_SURFACE_STATE_MAXIMIZED)
+ {
+ lastMaximizedFrame = newFrame;
+ [self windowDidUnmaximize];
+ }
+ else
+ {
+ lastUnmaximizedFrame = [nsWindow frame];
+ gdk_synthesize_surface_state (GDK_SURFACE (gdk_surface), 0, GDK_SURFACE_STATE_MAXIMIZED);
+ }
+
+ inMaximizeTransition = YES;
+
+ return YES;
+}
+
+-(void)windowDidEndLiveResize:(NSNotification *)aNotification
+{
+ gboolean maximized = GDK_SURFACE (gdk_surface)->state & GDK_SURFACE_STATE_MAXIMIZED;
+
+ inMaximizeTransition = NO;
+
+ /* Even if this is CSD, we want to be opaque while maximized
+ * to speed up compositing by allowing the display server to
+ * avoid costly blends.
+ */
+ if (maximized)
+ [self setOpaque:YES];
+}
+
+-(NSSize)window:(NSWindow *)window willUseFullScreenContentSize:(NSSize)proposedSize
+{
+ return [[window screen] frame].size;
+}
+
+-(void)windowWillEnterFullScreen:(NSNotification *)aNotification
+{
+ lastUnfullscreenFrame = [self frame];
+}
+
+-(void)windowWillExitFullScreen:(NSNotification *)aNotification
+{
+ [self setFrame:lastUnfullscreenFrame display:YES];
+}
+
+-(void)windowDidExitFullScreen:(NSNotification *)aNotification
+{
+}
+
+-(void)windowDidChangeScreen:(NSNotification *)aNotification
+{
+ _gdk_macos_surface_monitor_changed (gdk_surface);
+}
+
+-(void)setGdkSurface:(GdkMacosSurface *)surface
+{
+ self->gdk_surface = surface;
+}
+
+-(void)setDecorated:(BOOL)decorated
+{
+ NSWindowStyleMask style_mask = [self styleMask];
+
+ [self setHasShadow:decorated];
+
+ if (decorated)
+ style_mask |= NSWindowStyleMaskTitled;
+ else
+ style_mask &= ~NSWindowStyleMaskTitled;
+
+ [self setStyleMask:style_mask];
+}
+
+-(GdkMacosSurface *)gdkSurface
+{
+ return self->gdk_surface;
+}
+
+-(GdkMacosDisplay *)gdkDisplay
+{
+ return GDK_MACOS_DISPLAY (GDK_SURFACE (self->gdk_surface)->display);
+}
+
+-(BOOL)movableByWindowBackground
+{
+ return NO;
+}
+
+@end
--- /dev/null
+/* GdkMacosWindow.h
+ *
+ * Copyright © 2020 Red Hat, Inc.
+ * Copyright © 2005-2007 Imendio AB
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#import <AppKit/AppKit.h>
+#import <Foundation/Foundation.h>
+
+#include <gdk/gdk.h>
+
+#include "gdkmacosdisplay.h"
+#include "gdkmacossurface.h"
+#include "edgesnapping.h"
+
+#define GDK_IS_MACOS_WINDOW(obj) ([obj isKindOfClass:[GdkMacosWindow class]])
+
+@interface GdkMacosWindow : NSWindow {
+ GdkMacosSurface *gdk_surface;
+
+ BOOL inMove;
+ BOOL inShowOrHide;
+ BOOL initialPositionKnown;
+
+ /* Manually triggered move/resize (not by the window manager) */
+ BOOL inManualMove;
+ BOOL inManualResize;
+ BOOL inTrackManualResize;
+ NSPoint initialResizeLocation;
+ NSRect initialResizeFrame;
+ GdkSurfaceEdge resizeEdge;
+
+ EdgeSnapping snapping;
+
+ NSRect lastUnmaximizedFrame;
+ NSRect lastMaximizedFrame;
+ NSRect lastUnfullscreenFrame;
+ BOOL inMaximizeTransition;
+}
+
+-(void)beginManualMove;
+-(void)beginManualResize:(GdkSurfaceEdge)edge;
+-(void)hide;
+-(BOOL)isInManualResizeOrMove;
+-(BOOL)isInMove;
+-(GdkMacosDisplay *)gdkDisplay;
+-(GdkMacosSurface *)gdkSurface;
+-(void)setGdkSurface:(GdkMacosSurface *)surface;
+-(void)setStyleMask:(NSWindowStyleMask)styleMask;
+-(void)showAndMakeKey:(BOOL)makeKey;
+-(BOOL)trackManualMove;
+-(BOOL)trackManualResize;
+-(void)setDecorated:(BOOL)decorated;
+
+@end
--- /dev/null
+/* edgesnapping.c
+ *
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#include "gdkrectangle.h"
+#include "edgesnapping.h"
+
+#define LEAVE_THRESHOLD 3.0
+#define ENTER_THRESHOLD 2.0
+
+#define X1(r) ((r)->x)
+#define X2(r) ((r)->x + (r)->width)
+#define Y1(r) ((r)->y)
+#define Y2(r) ((r)->y + (r)->height)
+
+void
+_edge_snapping_init (EdgeSnapping *self,
+ const GdkRectangle *geometry,
+ const GdkRectangle *workarea,
+ const GdkPoint *pointer_position,
+ const GdkRectangle *window)
+{
+ g_assert (self != NULL);
+ g_assert (geometry != NULL);
+ g_assert (workarea != NULL);
+ g_assert (pointer_position != NULL);
+
+ self->geometry = *geometry;
+ self->workarea = *workarea;
+ self->last_pointer_position = *pointer_position;
+ self->pointer_offset_in_window.x = pointer_position->x - window->x;
+ self->pointer_offset_in_window.y = pointer_position->y - window->y;
+}
+
+static void
+edge_snapping_constrain_left (EdgeSnapping *self,
+ int change,
+ const GdkRectangle *geometry,
+ GdkRectangle *window)
+{
+ if (change < 0)
+ {
+ if (X1 (window) < X1 (geometry) &&
+ X1 (window) > X1 (geometry) - LEAVE_THRESHOLD &&
+ ABS (change) < LEAVE_THRESHOLD)
+ window->x = geometry->x;
+ }
+
+ /* We don't constrain when returning from left edge */
+}
+
+static void
+edge_snapping_constrain_right (EdgeSnapping *self,
+ int change,
+ const GdkRectangle *geometry,
+ GdkRectangle *window)
+{
+ if (change > 0)
+ {
+ if (X2 (window) > X2 (geometry) &&
+ X2 (window) < X2 (geometry) + LEAVE_THRESHOLD &&
+ ABS (change) < LEAVE_THRESHOLD)
+ window->x = X2 (geometry) - window->width;
+ }
+
+ /* We don't constrain when returning from right edge */
+}
+
+static void
+edge_snapping_constrain_top (EdgeSnapping *self,
+ int change,
+ const GdkRectangle *geometry,
+ GdkRectangle *window)
+{
+ if (change < 0)
+ {
+ if (Y1 (window) < Y1 (geometry))
+ window->y = geometry->y;
+ }
+
+ /* We don't constrain when returning from top edge */
+}
+
+static void
+edge_snapping_constrain_bottom (EdgeSnapping *self,
+ int change,
+ const GdkRectangle *geometry,
+ GdkRectangle *window)
+{
+ if (change > 0)
+ {
+ if (Y2 (window) > Y2 (geometry) &&
+ Y2 (window) < Y2 (geometry) + LEAVE_THRESHOLD &&
+ ABS (change) < LEAVE_THRESHOLD)
+ window->y = Y2 (geometry) - window->height;
+ }
+ else if (change < 0)
+ {
+ if (Y2 (window) < Y2 (geometry) &&
+ Y2 (window) > Y2 (geometry) - ENTER_THRESHOLD &&
+ ABS (change) < ENTER_THRESHOLD)
+ window->y = Y2 (geometry) - window->height;
+ }
+
+}
+
+static void
+edge_snapping_constrain_horizontal (EdgeSnapping *self,
+ int change,
+ const GdkRectangle *geometry,
+ GdkRectangle *window)
+{
+ g_assert (self != NULL);
+ g_assert (geometry != NULL);
+ g_assert (window != NULL);
+ g_assert (change != 0);
+
+ if (ABS (X1 (geometry) - X1 (window)) < ABS (X2 (geometry)) - ABS (X2 (window)))
+ edge_snapping_constrain_left (self, change, geometry, window);
+ else
+ edge_snapping_constrain_right (self, change, geometry, window);
+}
+
+static void
+edge_snapping_constrain_vertical (EdgeSnapping *self,
+ int change,
+ const GdkRectangle *geometry,
+ GdkRectangle *window,
+ gboolean bottom_only)
+{
+ g_assert (self != NULL);
+ g_assert (geometry != NULL);
+ g_assert (window != NULL);
+ g_assert (change != 0);
+
+ if (!bottom_only &&
+ ABS (Y1 (geometry) - Y1 (window)) < ABS (Y2 (geometry)) - ABS (Y2 (window)))
+ edge_snapping_constrain_top (self, change, geometry, window);
+ else
+ edge_snapping_constrain_bottom (self, change, geometry, window);
+}
+
+void
+_edge_snapping_motion (EdgeSnapping *self,
+ const GdkPoint *pointer_position,
+ GdkRectangle *window)
+{
+ GdkRectangle new_window;
+ GdkRectangle overlap;
+ GdkPoint change;
+
+ g_assert (self != NULL);
+ g_assert (pointer_position != NULL);
+
+ change.x = pointer_position->x - self->last_pointer_position.x;
+ change.y = pointer_position->y - self->last_pointer_position.y;
+
+ self->last_pointer_position = *pointer_position;
+
+ window->x += change.x;
+ window->y += change.y;
+
+ new_window = *window;
+
+ /* First constrain horizontal */
+ if (change.x)
+ {
+ edge_snapping_constrain_horizontal (self, change.x, &self->workarea, &new_window);
+ if (gdk_rectangle_equal (&new_window, window))
+ edge_snapping_constrain_horizontal (self, change.x, &self->geometry, &new_window);
+ }
+
+ /* Now constrain veritcally */
+ if (change.y)
+ {
+ edge_snapping_constrain_vertical (self, change.y, &self->workarea, &new_window, FALSE);
+ if (new_window.y == window->y)
+ edge_snapping_constrain_vertical (self, change.y, &self->geometry, &new_window, TRUE);
+ }
+
+ /* If the window is not placed in the monitor at all, then we need to
+ * just move the window onto the new screen using the original offset
+ * of the pointer within the window.
+ */
+ if (!gdk_rectangle_intersect (&self->geometry, &new_window, &overlap))
+ {
+ new_window.x = pointer_position->x - self->pointer_offset_in_window.x;
+ new_window.y = pointer_position->y - self->pointer_offset_in_window.y;
+ }
+
+ /* And finally make sure we aren't underneath the top bar of the
+ * particular monitor.
+ */
+ if (Y1 (&new_window) < Y1 (&self->workarea))
+ new_window.y = self->workarea.y;
+
+ *window = new_window;
+}
+
+void
+_edge_snapping_set_monitor (EdgeSnapping *self,
+ const GdkRectangle *geometry,
+ const GdkRectangle *workarea)
+{
+ g_assert (self != NULL);
+ g_assert (geometry != NULL);
+ g_assert (workarea != NULL);
+
+ self->geometry = *geometry;
+ self->workarea = *workarea;
+}
--- /dev/null
+/* edgesnapping.h
+ *
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef __EDGE_SNAPPING_H__
+#define __EDGE_SNAPPING_H__
+
+#include "gdktypes.h"
+
+G_BEGIN_DECLS
+
+typedef struct
+{
+ GdkRectangle geometry;
+ GdkRectangle workarea;
+ GdkPoint last_pointer_position;
+ GdkPoint pointer_offset_in_window;
+} EdgeSnapping;
+
+void _edge_snapping_init (EdgeSnapping *self,
+ const GdkRectangle *geometry,
+ const GdkRectangle *workarea,
+ const GdkPoint *pointer_position,
+ const GdkRectangle *window);
+void _edge_snapping_motion (EdgeSnapping *self,
+ const GdkPoint *pointer_position,
+ GdkRectangle *window);
+void _edge_snapping_set_monitor (EdgeSnapping *self,
+ const GdkRectangle *geometry,
+ const GdkRectangle *workarea);
+
+G_END_DECLS
+
+#endif /* __EDGE_SNAPPING_H__ */
--- /dev/null
+/* gdkdisplaylinksource.c
+ *
+ * Copyright (C) 2015 Christian Hergert <christian@hergert.me>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Christian Hergert <christian@hergert.me>
+ */
+
+#include "config.h"
+
+#include <AppKit/AppKit.h>
+#include <mach/mach_time.h>
+
+#include "gdkdisplaylinksource.h"
+
+#include "gdkmacoseventsource-private.h"
+
+static gint64 host_to_frame_clock_time (gint64 host_time);
+
+static gboolean
+gdk_display_link_source_prepare (GSource *source,
+ gint *timeout_)
+{
+ GdkDisplayLinkSource *impl = (GdkDisplayLinkSource *)source;
+ gint64 now;
+
+ now = g_source_get_time (source);
+
+ if (now < impl->presentation_time)
+ *timeout_ = (impl->presentation_time - now) / 1000L;
+ else
+ *timeout_ = -1;
+
+ return impl->needs_dispatch;
+}
+
+static gboolean
+gdk_display_link_source_check (GSource *source)
+{
+ GdkDisplayLinkSource *impl = (GdkDisplayLinkSource *)source;
+ return impl->needs_dispatch;
+}
+
+static gboolean
+gdk_display_link_source_dispatch (GSource *source,
+ GSourceFunc callback,
+ gpointer user_data)
+{
+ GdkDisplayLinkSource *impl = (GdkDisplayLinkSource *)source;
+ gboolean ret = G_SOURCE_CONTINUE;
+
+ impl->needs_dispatch = FALSE;
+
+ if (callback != NULL)
+ ret = callback (user_data);
+
+ return ret;
+}
+
+static void
+gdk_display_link_source_finalize (GSource *source)
+{
+ GdkDisplayLinkSource *impl = (GdkDisplayLinkSource *)source;
+
+ CVDisplayLinkStop (impl->display_link);
+ CVDisplayLinkRelease (impl->display_link);
+}
+
+static GSourceFuncs gdk_display_link_source_funcs = {
+ gdk_display_link_source_prepare,
+ gdk_display_link_source_check,
+ gdk_display_link_source_dispatch,
+ gdk_display_link_source_finalize
+};
+
+void
+gdk_display_link_source_pause (GdkDisplayLinkSource *source)
+{
+ CVDisplayLinkStop (source->display_link);
+}
+
+void
+gdk_display_link_source_unpause (GdkDisplayLinkSource *source)
+{
+ CVDisplayLinkStart (source->display_link);
+}
+
+static CVReturn
+gdk_display_link_source_frame_cb (CVDisplayLinkRef display_link,
+ const CVTimeStamp *inNow,
+ const CVTimeStamp *inOutputTime,
+ CVOptionFlags flagsIn,
+ CVOptionFlags *flagsOut,
+ void *user_data)
+{
+ GdkDisplayLinkSource *impl = user_data;
+ gint64 presentation_time;
+ gboolean needs_wakeup;
+
+ needs_wakeup = !g_atomic_int_get (&impl->needs_dispatch);
+
+ presentation_time = host_to_frame_clock_time (inOutputTime->hostTime);
+
+ impl->presentation_time = presentation_time;
+ impl->needs_dispatch = TRUE;
+
+ if (needs_wakeup)
+ {
+ NSEvent *event;
+
+ /* Post a message so we'll break out of the message loop.
+ *
+ * We don't use g_main_context_wakeup() here because that
+ * would result in sending a message to the pipe(2) fd in
+ * the select thread which would then send this message as
+ * well. Lots of extra work.
+ */
+ event = [NSEvent otherEventWithType: NSEventTypeApplicationDefined
+ location: NSZeroPoint
+ modifierFlags: 0
+ timestamp: 0
+ windowNumber: 0
+ context: nil
+ subtype: GDK_MACOS_EVENT_SUBTYPE_EVENTLOOP
+ data1: 0
+ data2: 0];
+
+ [NSApp postEvent:event atStart:YES];
+ }
+
+ return kCVReturnSuccess;
+}
+
+/**
+ * gdk_display_link_source_new:
+ *
+ * Creates a new #GSource that will activate the dispatch function upon
+ * notification from a CVDisplayLink that a new frame should be drawn.
+ *
+ * Effort is made to keep the transition from the high-priority
+ * CVDisplayLink thread into this GSource lightweight. However, this is
+ * somewhat non-ideal since the best case would be to do the drawing
+ * from the high-priority thread.
+ *
+ * Returns: (transfer full): A newly created #GSource.
+ */
+GSource *
+gdk_display_link_source_new (void)
+{
+ GdkDisplayLinkSource *impl;
+ GSource *source;
+ CVReturn ret;
+ double period;
+
+ source = g_source_new (&gdk_display_link_source_funcs, sizeof *impl);
+ impl = (GdkDisplayLinkSource *)source;
+
+ /*
+ * Create our link based on currently connected displays.
+ * If there are multiple displays, this will be something that tries
+ * to work for all of them. In the future, we may want to explore multiple
+ * links based on the connected displays.
+ */
+ ret = CVDisplayLinkCreateWithActiveCGDisplays (&impl->display_link);
+ if (ret != kCVReturnSuccess)
+ {
+ g_warning ("Failed to initialize CVDisplayLink!");
+ return source;
+ }
+
+ /*
+ * Determine our nominal period between frames.
+ */
+ period = CVDisplayLinkGetActualOutputVideoRefreshPeriod (impl->display_link);
+ if (period == 0.0)
+ period = 1.0 / 60.0;
+ impl->refresh_interval = period * 1000000L;
+ impl->refresh_rate = 1.0 / period * 1000L;
+
+ /*
+ * Wire up our callback to be executed within the high-priority thread.
+ */
+ CVDisplayLinkSetOutputCallback (impl->display_link,
+ gdk_display_link_source_frame_cb,
+ source);
+
+ g_source_set_name (source, "[gdk] quartz frame clock");
+
+ return source;
+}
+
+static gint64
+host_to_frame_clock_time (gint64 host_time)
+{
+ static mach_timebase_info_data_t timebase_info;
+
+ /*
+ * NOTE:
+ *
+ * This code is taken from GLib to match g_get_monotonic_time().
+ */
+ if (G_UNLIKELY (timebase_info.denom == 0))
+ {
+ /* This is a fraction that we must use to scale
+ * mach_absolute_time() by in order to reach nanoseconds.
+ *
+ * We've only ever observed this to be 1/1, but maybe it could be
+ * 1000/1 if mach time is microseconds already, or 1/1000 if
+ * picoseconds. Try to deal nicely with that.
+ */
+ mach_timebase_info (&timebase_info);
+
+ /* We actually want microseconds... */
+ if (timebase_info.numer % 1000 == 0)
+ timebase_info.numer /= 1000;
+ else
+ timebase_info.denom *= 1000;
+
+ /* We want to make the numer 1 to avoid having to multiply... */
+ if (timebase_info.denom % timebase_info.numer == 0)
+ {
+ timebase_info.denom /= timebase_info.numer;
+ timebase_info.numer = 1;
+ }
+ else
+ {
+ /* We could just multiply by timebase_info.numer below, but why
+ * bother for a case that may never actually exist...
+ *
+ * Plus -- performing the multiplication would risk integer
+ * overflow. If we ever actually end up in this situation, we
+ * should more carefully evaluate the correct course of action.
+ */
+ mach_timebase_info (&timebase_info); /* Get a fresh copy for a better message */
+ g_error ("Got weird mach timebase info of %d/%d. Please file a bug against GLib.",
+ timebase_info.numer, timebase_info.denom);
+ }
+ }
+
+ return host_time / timebase_info.denom;
+}
--- /dev/null
+/* gdkdisplaylinksource.h
+ *
+ * Copyright (C) 2015 Christian Hergert <christian@hergert.me>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Christian Hergert <christian@hergert.me>
+ */
+
+#ifndef GDK_DISPLAY_LINK_SOURCE_H
+#define GDK_DISPLAY_LINK_SOURCE_H
+
+#include <glib.h>
+
+#include <QuartzCore/QuartzCore.h>
+
+G_BEGIN_DECLS
+
+typedef struct
+{
+ GSource source;
+
+ CVDisplayLinkRef display_link;
+ gint64 refresh_interval;
+ guint refresh_rate;
+
+ volatile gint64 presentation_time;
+ volatile guint needs_dispatch;
+} GdkDisplayLinkSource;
+
+GSource *gdk_display_link_source_new (void);
+void gdk_display_link_source_pause (GdkDisplayLinkSource *source);
+void gdk_display_link_source_unpause (GdkDisplayLinkSource *source);
+
+G_END_DECLS
+
+#endif /* GDK_DISPLAY_LINK_SOURCE_H */
--- /dev/null
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef __GDK_MACOS_H__
+#define __GDK_MACOS_H__
+
+#include <gdk/gdk.h>
+
+#include "gdkmacosdevice.h"
+#include "gdkmacosdisplay.h"
+#include "gdkmacosglcontext.h"
+#include "gdkmacoskeymap.h"
+#include "gdkmacosmonitor.h"
+#include "gdkmacossurface.h"
+
+#endif /* __GDK_MACOS_H__ */
--- /dev/null
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef __GDK_MACOS_CAIRO_CONTEXT_PRIVATE_H__
+#define __GDK_MACOS_CAIRO_CONTEXT_PRIVATE_H__
+
+#include "gdkcairocontextprivate.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GdkMacosCairoContext GdkMacosCairoContext;
+typedef struct _GdkMacosCairoContextClass GdkMacosCairoContextClass;
+
+#define GDK_TYPE_MACOS_CAIRO_CONTEXT (_gdk_macos_cairo_context_get_type())
+#define GDK_MACOS_CAIRO_CONTEXT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_MACOS_CAIRO_CONTEXT, GdkMacosCairoContext))
+#define GDK_IS_MACOS_CAIRO_CONTEXT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MACOS_CAIRO_CONTEXT))
+
+GType _gdk_macos_cairo_context_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __GDK_MACOS_CAIRO_CONTEXT_PRIVATE_H__ */
--- /dev/null
+/*
+ * Copyright © 2016 Benjamin Otte
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#include "gdkconfig.h"
+
+#include <CoreGraphics/CoreGraphics.h>
+#include <cairo-quartz.h>
+
+#import "GdkMacosCairoView.h"
+
+#include "gdkmacoscairocontext-private.h"
+#include "gdkmacossurface-private.h"
+
+struct _GdkMacosCairoContext
+{
+ GdkCairoContext parent_instance;
+
+ cairo_surface_t *window_surface;
+};
+
+struct _GdkMacosCairoContextClass
+{
+ GdkCairoContextClass parent_class;
+};
+
+G_DEFINE_TYPE (GdkMacosCairoContext, _gdk_macos_cairo_context, GDK_TYPE_CAIRO_CONTEXT)
+
+static cairo_surface_t *
+create_cairo_surface_for_surface (GdkSurface *surface)
+{
+ cairo_surface_t *cairo_surface;
+ int scale;
+ int width;
+ int height;
+
+ g_assert (GDK_IS_MACOS_SURFACE (surface));
+
+ scale = gdk_surface_get_scale_factor (surface);
+ width = scale * gdk_surface_get_width (surface);
+ height = scale * gdk_surface_get_height (surface);
+
+ cairo_surface = cairo_quartz_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+
+ if (cairo_surface != NULL)
+ cairo_surface_set_device_scale (cairo_surface, scale, scale);
+
+ return cairo_surface;
+}
+
+static cairo_t *
+_gdk_macos_cairo_context_cairo_create (GdkCairoContext *cairo_context)
+{
+ GdkMacosCairoContext *self = (GdkMacosCairoContext *)cairo_context;
+
+ g_assert (GDK_IS_MACOS_CAIRO_CONTEXT (self));
+
+ return cairo_create (self->window_surface);
+}
+
+static void
+_gdk_macos_cairo_context_begin_frame (GdkDrawContext *draw_context,
+ cairo_region_t *region)
+{
+ GdkMacosCairoContext *self = (GdkMacosCairoContext *)draw_context;
+ GdkSurface *surface;
+ NSWindow *nswindow;
+
+ g_assert (GDK_IS_MACOS_CAIRO_CONTEXT (self));
+
+ surface = gdk_draw_context_get_surface (draw_context);
+ nswindow = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (surface));
+
+ if (self->window_surface == NULL)
+ {
+ self->window_surface = create_cairo_surface_for_surface (surface);
+ }
+ else
+ {
+ if (![nswindow isOpaque])
+ {
+ cairo_t *cr = cairo_create (self->window_surface);
+ gdk_cairo_region (cr, region);
+ cairo_set_source_rgba (cr, 0, 0, 0, 0);
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_fill (cr);
+ cairo_destroy (cr);
+ }
+ }
+}
+
+static void
+_gdk_macos_cairo_context_end_frame (GdkDrawContext *draw_context,
+ cairo_region_t *painted)
+{
+ GdkMacosCairoContext *self = (GdkMacosCairoContext *)draw_context;
+ GdkSurface *surface;
+ NSView *nsview;
+
+ g_assert (GDK_IS_MACOS_CAIRO_CONTEXT (self));
+ g_assert (self->window_surface != NULL);
+
+ surface = gdk_draw_context_get_surface (draw_context);
+ nsview = _gdk_macos_surface_get_view (GDK_MACOS_SURFACE (surface));
+
+ if (GDK_IS_MACOS_CAIRO_VIEW (nsview))
+ [(GdkMacosCairoView *)nsview setCairoSurface:self->window_surface
+ withDamage:painted];
+}
+
+static void
+_gdk_macos_cairo_context_surface_resized (GdkDrawContext *draw_context)
+{
+ GdkMacosCairoContext *self = (GdkMacosCairoContext *)draw_context;
+
+ g_assert (GDK_IS_MACOS_CAIRO_CONTEXT (self));
+
+ g_clear_pointer (&self->window_surface, cairo_surface_destroy);
+}
+
+static void
+_gdk_macos_cairo_context_class_init (GdkMacosCairoContextClass *klass)
+{
+ GdkCairoContextClass *cairo_context_class = GDK_CAIRO_CONTEXT_CLASS (klass);
+ GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS (klass);
+
+ draw_context_class->begin_frame = _gdk_macos_cairo_context_begin_frame;
+ draw_context_class->end_frame = _gdk_macos_cairo_context_end_frame;
+ draw_context_class->surface_resized = _gdk_macos_cairo_context_surface_resized;
+
+ cairo_context_class->cairo_create = _gdk_macos_cairo_context_cairo_create;
+}
+
+static void
+_gdk_macos_cairo_context_init (GdkMacosCairoContext *self)
+{
+}
--- /dev/null
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef __GDK_MACOS_CLIPBOARD_PRIVATE_H__
+#define __GDK_MACOS_CLIPBOARD_PRIVATE_H__
+
+#include <AppKit/AppKit.h>
+
+#include "gdkclipboardprivate.h"
+#include "gdkmacosdisplay-private.h"
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_MACOS_CLIPBOARD (_gdk_macos_clipboard_get_type())
+
+G_DECLARE_FINAL_TYPE (GdkMacosClipboard, _gdk_macos_clipboard, GDK, MACOS_CLIPBOARD, GdkClipboard)
+
+GdkClipboard *_gdk_macos_clipboard_new (GdkMacosDisplay *display);
+void _gdk_macos_clipboard_check_externally_modified (GdkMacosClipboard *self);
+NSPasteboardType _gdk_macos_clipboard_to_ns_type (const char *mime_type,
+ NSPasteboardType *alternate);
+const char *_gdk_macos_clipboard_from_ns_type (NSPasteboardType ns_type);
+
+@interface GdkMacosClipboardDataProvider : NSObject <NSPasteboardItemDataProvider>
+{
+ GCancellable *cancellable;
+ GdkClipboard *clipboard;
+ char **mimeTypes;
+}
+
+-(id)initClipboard:(GdkClipboard *)gdkClipboard mimetypes:(const char * const *)mime_types;
+-(NSArray<NSPasteboardType> *)types;
+
+@end
+
+G_END_DECLS
+
+#endif /* __GDK_MACOS_CLIPBOARD_PRIVATE_H__ */
--- /dev/null
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+
+#include "gdkmacosclipboard-private.h"
+#include "gdkmacosutils-private.h"
+
+struct _GdkMacosClipboard
+{
+ GdkClipboard parent_instance;
+ NSPasteboard *pasteboard;
+ NSInteger last_change_count;
+};
+
+typedef struct
+{
+ GMemoryOutputStream *stream;
+ NSPasteboardItem *item;
+ NSPasteboardType type;
+ GMainContext *main_context;
+ guint done : 1;
+} WriteRequest;
+
+G_DEFINE_TYPE (GdkMacosClipboard, _gdk_macos_clipboard, GDK_TYPE_CLIPBOARD)
+
+static void
+write_request_free (WriteRequest *wr)
+{
+ g_clear_pointer (&wr->main_context, g_main_context_unref);
+ g_clear_object (&wr->stream);
+ [wr->item release];
+ g_slice_free (WriteRequest, wr);
+}
+
+const char *
+_gdk_macos_clipboard_from_ns_type (NSPasteboardType type)
+{
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+
+ if ([type isEqualToString:NSPasteboardTypeString] ||
+ [type isEqualToString:NSStringPboardType])
+ return g_intern_string ("text/plain;charset=utf-8");
+ else if ([type isEqualToString:NSPasteboardTypeURL] ||
+ [type isEqualToString:NSPasteboardTypeFileURL])
+ return g_intern_string ("text/uri-list");
+ else if ([type isEqualToString:NSPasteboardTypeColor])
+ return g_intern_string ("application/x-color");
+ else if ([type isEqualToString:NSPasteboardTypeTIFF])
+ return g_intern_string ("image/tiff");
+ else if ([type isEqualToString:NSPasteboardTypePNG])
+ return g_intern_string ("image/png");
+
+ G_GNUC_END_IGNORE_DEPRECATIONS;
+
+ return NULL;
+}
+
+NSPasteboardType
+_gdk_macos_clipboard_to_ns_type (const char *mime_type,
+ NSPasteboardType *alternate)
+{
+ if (alternate)
+ *alternate = NULL;
+
+ if (g_strcmp0 (mime_type, "text/plain;charset=utf-8") == 0)
+ {
+ return NSPasteboardTypeString;
+ }
+ else if (g_strcmp0 (mime_type, "text/uri-list") == 0)
+ {
+ if (alternate)
+ *alternate = NSPasteboardTypeURL;
+ return NSPasteboardTypeFileURL;
+ }
+ else if (g_strcmp0 (mime_type, "application/x-color") == 0)
+ {
+ return NSPasteboardTypeColor;
+ }
+ else if (g_strcmp0 (mime_type, "image/tiff") == 0)
+ {
+ return NSPasteboardTypeTIFF;
+ }
+ else if (g_strcmp0 (mime_type, "image/png") == 0)
+ {
+ return NSPasteboardTypePNG;
+ }
+
+ return nil;
+}
+
+static void
+populate_content_formats (GdkContentFormatsBuilder *builder,
+ NSPasteboardType type)
+{
+ const char *mime_type;
+
+ g_return_if_fail (builder != NULL);
+ g_return_if_fail (type != NULL);
+
+ mime_type = _gdk_macos_clipboard_from_ns_type (type);
+
+ if (mime_type != NULL)
+ gdk_content_formats_builder_add_mime_type (builder, mime_type);
+}
+
+static GdkContentFormats *
+load_offer_formats (GdkMacosClipboard *self)
+{
+ GDK_BEGIN_MACOS_ALLOC_POOL;
+
+ GdkContentFormatsBuilder *builder;
+ GdkContentFormats *formats;
+
+ g_assert (GDK_IS_MACOS_CLIPBOARD (self));
+
+ builder = gdk_content_formats_builder_new ();
+ for (NSPasteboardType type in [self->pasteboard types])
+ populate_content_formats (builder, type);
+ formats = gdk_content_formats_builder_free_to_formats (builder);
+
+ GDK_END_MACOS_ALLOC_POOL;
+
+ return g_steal_pointer (&formats);
+}
+
+static void
+_gdk_macos_clipboard_load_contents (GdkMacosClipboard *self)
+{
+ GdkContentFormats *formats;
+ NSInteger change_count;
+
+ g_assert (GDK_IS_MACOS_CLIPBOARD (self));
+
+ change_count = [self->pasteboard changeCount];
+
+ formats = load_offer_formats (self);
+ gdk_clipboard_claim_remote (GDK_CLIPBOARD (self), formats);
+ gdk_content_formats_unref (formats);
+
+ self->last_change_count = change_count;
+}
+
+static GInputStream *
+create_stream_from_nsdata (NSData *data)
+{
+ const guint8 *bytes = [data bytes];
+ gsize len = [data length];
+
+ return g_memory_input_stream_new_from_data (g_memdup (bytes, len), len, g_free);
+}
+
+static void
+_gdk_macos_clipboard_read_async (GdkClipboard *clipboard,
+ GdkContentFormats *formats,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GDK_BEGIN_MACOS_ALLOC_POOL;
+
+ GdkMacosClipboard *self = (GdkMacosClipboard *)clipboard;
+ GdkContentFormats *offer_formats = NULL;
+ const char *mime_type;
+ GInputStream *stream = NULL;
+ GTask *task = NULL;
+
+ g_assert (GDK_IS_MACOS_CLIPBOARD (self));
+ g_assert (formats != NULL);
+
+ task = g_task_new (self, cancellable, callback, user_data);
+ g_task_set_source_tag (task, _gdk_macos_clipboard_read_async);
+ g_task_set_priority (task, io_priority);
+
+ offer_formats = load_offer_formats (GDK_MACOS_CLIPBOARD (clipboard));
+ mime_type = gdk_content_formats_match_mime_type (formats, offer_formats);
+
+ if (mime_type == NULL)
+ {
+ g_task_return_new_error (task,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ "%s",
+ _("No compatible transfer format found"));
+ goto cleanup;
+ }
+
+ if (strcmp (mime_type, "text/plain;charset=utf-8") == 0)
+ {
+ NSString *nsstr = [self->pasteboard stringForType:NSPasteboardTypeString];
+
+ if (nsstr != NULL)
+ {
+ const char *str = [nsstr UTF8String];
+ stream = g_memory_input_stream_new_from_data (g_strdup (str),
+ strlen (str) + 1,
+ g_free);
+ }
+ }
+ else if (strcmp (mime_type, "text/uri-list") == 0)
+ {
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+
+ if ([[self->pasteboard types] containsObject:NSPasteboardTypeFileURL])
+ {
+ GString *str = g_string_new (NULL);
+ NSArray *files = [self->pasteboard propertyListForType:NSFilenamesPboardType];
+ gsize n_files = [files count];
+ char *data;
+ guint len;
+
+ for (gsize i = 0; i < n_files; ++i)
+ {
+ NSString* uriString = [files objectAtIndex:i];
+ uriString = [@"file://" stringByAppendingString:uriString];
+ uriString = [uriString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+
+ g_string_append_printf (str,
+ "%s\r\n",
+ [uriString cStringUsingEncoding:NSUTF8StringEncoding]);
+ }
+
+ len = str->len;
+ data = g_string_free (str, FALSE);
+ stream = g_memory_input_stream_new_from_data (data, len, g_free);
+ }
+
+ G_GNUC_END_IGNORE_DEPRECATIONS;
+ }
+ else if (strcmp (mime_type, "application/x-color") == 0)
+ {
+ NSColorSpace *colorspace;
+ NSColor *nscolor;
+ guint16 color[4];
+
+ colorspace = [NSColorSpace genericRGBColorSpace];
+ nscolor = [[NSColor colorFromPasteboard:self->pasteboard]
+ colorUsingColorSpace:colorspace];
+
+ color[0] = 0xffff * [nscolor redComponent];
+ color[1] = 0xffff * [nscolor greenComponent];
+ color[2] = 0xffff * [nscolor blueComponent];
+ color[3] = 0xffff * [nscolor alphaComponent];
+
+ stream = g_memory_input_stream_new_from_data (g_memdup (&color, sizeof color),
+ sizeof color,
+ g_free);
+ }
+ else if (strcmp (mime_type, "image/tiff") == 0)
+ {
+ NSData *data = [self->pasteboard dataForType:NSPasteboardTypeTIFF];
+ stream = create_stream_from_nsdata (data);
+ }
+ else if (strcmp (mime_type, "image/png") == 0)
+ {
+ NSData *data = [self->pasteboard dataForType:NSPasteboardTypePNG];
+ stream = create_stream_from_nsdata (data);
+ }
+
+ if (stream != NULL)
+ {
+ g_task_set_task_data (task, g_strdup (mime_type), g_free);
+ g_task_return_pointer (task, g_steal_pointer (&stream), g_object_unref);
+ }
+ else
+ {
+ g_task_return_new_error (task,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ _("Failed to decode contents with mime-type of '%s'"),
+ mime_type);
+ }
+
+cleanup:
+ g_clear_object (&task);
+ g_clear_pointer (&offer_formats, gdk_content_formats_unref);
+
+ GDK_END_MACOS_ALLOC_POOL;
+}
+
+static GInputStream *
+_gdk_macos_clipboard_read_finish (GdkClipboard *clipboard,
+ GAsyncResult *result,
+ const char **out_mime_type,
+ GError **error)
+{
+ GTask *task = (GTask *)result;
+
+ g_assert (GDK_IS_MACOS_CLIPBOARD (clipboard));
+ g_assert (G_IS_TASK (task));
+
+ if (out_mime_type != NULL)
+ *out_mime_type = g_strdup (g_task_get_task_data (task));
+
+ return g_task_propagate_pointer (task, error);
+}
+
+static void
+_gdk_macos_clipboard_send_to_pasteboard (GdkMacosClipboard *self,
+ GdkContentProvider *content)
+{
+ GDK_BEGIN_MACOS_ALLOC_POOL;
+
+ GdkMacosClipboardDataProvider *dataProvider;
+ GdkContentFormats *serializable;
+ NSPasteboardItem *item;
+ const char * const *mime_types;
+ gsize n_mime_types;
+
+ g_return_if_fail (GDK_IS_MACOS_CLIPBOARD (self));
+ g_return_if_fail (GDK_IS_CONTENT_PROVIDER (content));
+
+ serializable = gdk_content_provider_ref_storable_formats (content);
+ serializable = gdk_content_formats_union_serialize_mime_types (serializable);
+ mime_types = gdk_content_formats_get_mime_types (serializable, &n_mime_types);
+
+ dataProvider = [[GdkMacosClipboardDataProvider alloc] initClipboard:GDK_CLIPBOARD (self)
+ mimetypes:mime_types];
+ item = [[NSPasteboardItem alloc] init];
+ [item setDataProvider:dataProvider forTypes:[dataProvider types]];
+
+ [self->pasteboard clearContents];
+ if ([self->pasteboard writeObjects:[NSArray arrayWithObject:item]] == NO)
+ g_warning ("Failed to write object to pasteboard");
+
+ self->last_change_count = [self->pasteboard changeCount];
+
+ g_clear_pointer (&serializable, gdk_content_formats_unref);
+
+ GDK_END_MACOS_ALLOC_POOL;
+}
+
+static gboolean
+_gdk_macos_clipboard_claim (GdkClipboard *clipboard,
+ GdkContentFormats *formats,
+ gboolean local,
+ GdkContentProvider *provider)
+{
+ GdkMacosClipboard *self = (GdkMacosClipboard *)clipboard;
+ gboolean ret;
+
+ g_assert (GDK_IS_CLIPBOARD (clipboard));
+ g_assert (formats != NULL);
+ g_assert (!provider || GDK_IS_CONTENT_PROVIDER (provider));
+
+ ret = GDK_CLIPBOARD_CLASS (_gdk_macos_clipboard_parent_class)->claim (clipboard, formats, local, provider);
+
+ if (local)
+ _gdk_macos_clipboard_send_to_pasteboard (self, provider);
+
+ return ret;
+}
+
+static void
+_gdk_macos_clipboard_constructed (GObject *object)
+{
+ GdkMacosClipboard *self = (GdkMacosClipboard *)object;
+
+ if (self->pasteboard == nil)
+ self->pasteboard = [[NSPasteboard generalPasteboard] retain];
+
+ G_OBJECT_CLASS (_gdk_macos_clipboard_parent_class)->constructed (object);
+}
+
+static void
+_gdk_macos_clipboard_finalize (GObject *object)
+{
+ GdkMacosClipboard *self = (GdkMacosClipboard *)object;
+
+ if (self->pasteboard != nil)
+ {
+ [self->pasteboard release];
+ self->pasteboard = nil;
+ }
+
+ G_OBJECT_CLASS (_gdk_macos_clipboard_parent_class)->finalize (object);
+}
+
+static void
+_gdk_macos_clipboard_class_init (GdkMacosClipboardClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GdkClipboardClass *clipboard_class = GDK_CLIPBOARD_CLASS (klass);
+
+ object_class->constructed = _gdk_macos_clipboard_constructed;
+ object_class->finalize = _gdk_macos_clipboard_finalize;
+
+ clipboard_class->claim = _gdk_macos_clipboard_claim;
+ clipboard_class->read_async = _gdk_macos_clipboard_read_async;
+ clipboard_class->read_finish = _gdk_macos_clipboard_read_finish;
+}
+
+static void
+_gdk_macos_clipboard_init (GdkMacosClipboard *self)
+{
+}
+
+GdkClipboard *
+_gdk_macos_clipboard_new (GdkMacosDisplay *display)
+{
+ GdkMacosClipboard *self;
+
+ g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (display), NULL);
+
+ self = g_object_new (GDK_TYPE_MACOS_CLIPBOARD,
+ "display", display,
+ NULL);
+
+ _gdk_macos_clipboard_load_contents (self);
+
+ return GDK_CLIPBOARD (self);
+}
+
+void
+_gdk_macos_clipboard_check_externally_modified (GdkMacosClipboard *self)
+{
+ g_return_if_fail (GDK_IS_MACOS_CLIPBOARD (self));
+
+ if ([self->pasteboard changeCount] != self->last_change_count)
+ _gdk_macos_clipboard_load_contents (self);
+}
+
+@implementation GdkMacosClipboardDataProvider
+
+-(id)initClipboard:(GdkClipboard *)gdkClipboard mimetypes:(const char * const *)mime_types;
+{
+ [super init];
+
+ self->mimeTypes = g_strdupv ((char **)mime_types);
+ self->clipboard = g_object_ref (gdkClipboard);
+
+ return self;
+}
+
+-(void)dealloc
+{
+ g_cancellable_cancel (self->cancellable);
+
+ g_clear_pointer (&self->mimeTypes, g_strfreev);
+ g_clear_object (&self->clipboard);
+ g_clear_object (&self->cancellable);
+
+ [super dealloc];
+}
+
+-(void)pasteboardFinishedWithDataProvider:(NSPasteboard *)pasteboard
+{
+ g_clear_object (&self->clipboard);
+}
+
+-(NSArray<NSPasteboardType> *)types
+{
+ NSMutableArray *ret = [[NSMutableArray alloc] init];
+
+ for (guint i = 0; self->mimeTypes[i]; i++)
+ {
+ const char *mime_type = self->mimeTypes[i];
+ NSPasteboardType type;
+ NSPasteboardType alternate = nil;
+
+ if ((type = _gdk_macos_clipboard_to_ns_type (mime_type, &alternate)))
+ {
+ [ret addObject:type];
+ if (alternate)
+ [ret addObject:alternate];
+ }
+ }
+
+ return g_steal_pointer (&ret);
+}
+
+static void
+on_data_ready_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GDK_BEGIN_MACOS_ALLOC_POOL;
+
+ GdkClipboard *clipboard = (GdkClipboard *)object;
+ WriteRequest *wr = user_data;
+ GError *error = NULL;
+ NSData *data = nil;
+
+ g_assert (GDK_IS_CLIPBOARD (clipboard));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (wr != NULL);
+ g_assert (G_IS_MEMORY_OUTPUT_STREAM (wr->stream));
+ g_assert ([wr->item isKindOfClass:[NSPasteboardItem class]]);
+
+ if (gdk_clipboard_write_finish (clipboard, result, &error))
+ {
+ gsize size;
+ gpointer bytes;
+
+ g_output_stream_close (G_OUTPUT_STREAM (wr->stream), NULL, NULL);
+
+ size = g_memory_output_stream_get_size (wr->stream);
+ bytes = g_memory_output_stream_steal_data (wr->stream);
+ data = [[NSData alloc] initWithBytesNoCopy:bytes
+ length:size
+ deallocator:^(void *alloc, NSUInteger length) { g_free (alloc); }];
+ }
+ else
+ {
+ g_warning ("Failed to serialize clipboard contents: %s",
+ error->message);
+ g_clear_error (&error);
+ }
+
+ [wr->item setData:data forType:wr->type];
+
+ wr->done = TRUE;
+
+ GDK_END_MACOS_ALLOC_POOL;
+}
+
+-(void) pasteboard:(NSPasteboard *)pasteboard
+ item:(NSPasteboardItem *)item
+ provideDataForType:(NSPasteboardType)type
+{
+ const char *mime_type = _gdk_macos_clipboard_from_ns_type (type);
+ GMainContext *main_context = g_main_context_default ();
+ WriteRequest *wr;
+
+ if (self->clipboard == NULL || mime_type == NULL)
+ {
+ [item setData:[NSData data] forType:type];
+ return;
+ }
+
+ wr = g_slice_new0 (WriteRequest);
+ wr->item = [item retain];
+ wr->stream = G_MEMORY_OUTPUT_STREAM (g_memory_output_stream_new_resizable ());
+ wr->type = type;
+ wr->main_context = g_main_context_ref (main_context);
+ wr->done = FALSE;
+
+ gdk_clipboard_write_async (self->clipboard,
+ mime_type,
+ G_OUTPUT_STREAM (wr->stream),
+ G_PRIORITY_DEFAULT,
+ self->cancellable,
+ on_data_ready_cb,
+ wr);
+
+ /* We're forced to provide data synchronously via this API
+ * so we must block on the main loop. Using another main loop
+ * than the default tends to get us locked up here, so that is
+ * what we'll do for now.
+ */
+ while (!wr->done)
+ g_main_context_iteration (wr->main_context, TRUE);
+
+ write_request_free (wr);
+}
+
+@end
--- /dev/null
+/* gdkmacoscursor-private.h
+ *
+ * Copyright (C) 2005-2007 Imendio AB
+ * Copyright (C) 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GDK_MACOS_CURSOR_PRIVATE_H__
+#define __GDK_MACOS_CURSOR_PRIVATE_H__
+
+#include <AppKit/AppKit.h>
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+NSCursor *_gdk_macos_cursor_get_ns_cursor (GdkCursor *cursor);
+
+G_END_DECLS
+
+#endif /* __GDK_MACOS_CURSOR_PRIVATE_H__ */
--- /dev/null
+/* gdkcursor-macos.c
+ *
+ * Copyright (C) 2005-2007 Imendio AB
+ * Copyright (C) 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include "gdkmacoscursor-private.h"
+
+/* OS X only exports a number of cursor types in its public NSCursor interface.
+ * By overriding the private _coreCursorType method, we can tell OS X to load
+ * one of its internal cursors instead (since cursor images are loaded on demand
+ * instead of in advance). WebKit does this too.
+ */
+
+@interface gdkCoreCursor : NSCursor {
+@private
+ int type;
+ BOOL override;
+}
+@end
+
+@implementation gdkCoreCursor
+
+- (long long)_coreCursorType
+{
+ if (self->override)
+ return self->type;
+ return [super _coreCursorType];
+}
+
+#define CUSTOM_CURSOR_CTOR(name, id) \
+ + (gdkCoreCursor *)name \
+ { \
+ gdkCoreCursor *obj; \
+ obj = [self new]; \
+ if (obj) { \
+ obj->override = YES; \
+ obj->type = id; \
+ } \
+ return obj; \
+ }
+CUSTOM_CURSOR_CTOR(gdkHelpCursor, 40)
+CUSTOM_CURSOR_CTOR(gdkProgressCursor, 4)
+/* TODO OS X doesn't seem to have a way to get this. There is an undocumented
+ * method +[NSCursor _waitCursor], but it doesn't actually return this cursor,
+ * but rather some odd low-quality non-animating version of this cursor. Use
+ * the progress cursor instead for now.
+ */
+CUSTOM_CURSOR_CTOR(gdkWaitCursor, 4)
+CUSTOM_CURSOR_CTOR(gdkAliasCursor, 2)
+CUSTOM_CURSOR_CTOR(gdkMoveCursor, 39)
+/* TODO OS X doesn't seem to provide one; copy the move cursor for now
+ * since it looks similar to what we want. */
+CUSTOM_CURSOR_CTOR(gdkAllScrollCursor, 39)
+CUSTOM_CURSOR_CTOR(gdkNEResizeCursor, 29)
+CUSTOM_CURSOR_CTOR(gdkNWResizeCursor, 33)
+CUSTOM_CURSOR_CTOR(gdkSEResizeCursor, 35)
+CUSTOM_CURSOR_CTOR(gdkSWResizeCursor, 37)
+CUSTOM_CURSOR_CTOR(gdkEWResizeCursor, 28)
+CUSTOM_CURSOR_CTOR(gdkNSResizeCursor, 32)
+CUSTOM_CURSOR_CTOR(gdkNESWResizeCursor, 30)
+CUSTOM_CURSOR_CTOR(gdkNWSEResizeCursor, 34)
+CUSTOM_CURSOR_CTOR(gdkZoomInCursor, 42)
+CUSTOM_CURSOR_CTOR(gdkZoomOutCursor, 43)
+#undef CUSTOM_CURSOR_CTOR
+
+@end
+
+struct CursorsByName {
+ const gchar *name;
+ NSString *selector;
+};
+
+static const struct CursorsByName cursors_by_name[] = {
+ /* Link & Status */
+ { "context-menu", @"contextualMenuCursor" },
+ { "help", @"gdkHelpCursor" },
+ { "pointer", @"pointingHandCursor" },
+ { "progress", @"gdkProgressCursor" },
+ { "wait", @"gdkWaitCursor" },
+ /* Selection */
+ { "cell", @"crosshairCursor" },
+ { "crosshair", @"crosshairCursor" },
+ { "text", @"IBeamCursor" },
+ { "vertical-text", @"IBeamCursorForVerticalLayout" },
+ /* Drag & Drop */
+ { "alias", @"gdkAliasCursor" },
+ { "copy", @"dragCopyCursor" },
+ { "move", @"gdkMoveCursor" },
+ { "no-drop", @"operationNotAllowedCursor" },
+ { "not-allowed", @"operationNotAllowedCursor" },
+ { "grab", @"openHandCursor" },
+ { "grabbing", @"closedHandCursor" },
+ /* Resize & Scrolling */
+ { "all-scroll", @"gdkAllScrollCursor" },
+ { "col-resize", @"resizeLeftRightCursor" },
+ { "row-resize", @"resizeUpDownCursor" },
+
+ /* Undocumented cursors to match native resizing */
+ { "e-resize", @"_windowResizeEastWestCursor" },
+ { "w-resize", @"_windowResizeEastWestCursor" },
+ { "n-resize", @"_windowResizeNorthSouthCursor" },
+ { "s-resize", @"_windowResizeNorthSouthCursor" },
+
+ { "ne-resize", @"gdkNEResizeCursor" },
+ { "nw-resize", @"gdkNWResizeCursor" },
+ { "se-resize", @"gdkSEResizeCursor" },
+ { "sw-resize", @"gdkSWResizeCursor" },
+ { "ew-resize", @"gdkEWResizeCursor" },
+ { "ns-resize", @"gdkNSResizeCursor" },
+ { "nesw-resize", @"gdkNESWResizeCursor" },
+ { "nwse-resize", @"gdkNWSEResizeCursor" },
+ /* Zoom */
+ { "zoom-in", @"gdkZoomInCursor" },
+ { "zoom-out", @"gdkZoomOutCursor" },
+};
+
+static NSCursor *
+create_blank_cursor (void)
+{
+ NSCursor *nscursor;
+ NSImage *nsimage;
+ NSSize size = { 1.0, 1.0 };
+
+ nsimage = [[NSImage alloc] initWithSize:size];
+ nscursor = [[NSCursor alloc] initWithImage:nsimage
+ hotSpot:NSMakePoint(0.0, 0.0)];
+ [nsimage release];
+
+ return nscursor;
+}
+
+NSCursor *
+_gdk_macos_cursor_get_ns_cursor (GdkCursor *cursor)
+{
+ const char *name = NULL;
+ NSCursor *nscursor;
+ SEL selector = @selector(arrowCursor);
+
+ g_return_val_if_fail (!cursor || GDK_IS_CURSOR (cursor), NULL);
+
+ if (cursor != NULL)
+ name = gdk_cursor_get_name (cursor);
+
+ if (name == NULL)
+ goto load_cursor;
+
+ if (strcmp (name, "none") == 0)
+ return create_blank_cursor ();
+
+ for (guint i = 0; i < G_N_ELEMENTS (cursors_by_name); i++)
+ {
+ if (strcmp (cursors_by_name[i].name, name) == 0)
+ {
+ selector = NSSelectorFromString (cursors_by_name[i].selector);
+ break;
+ }
+ }
+
+load_cursor:
+ nscursor = [[gdkCoreCursor class] performSelector:selector];
+ [nscursor retain];
+ return nscursor;
+}
--- /dev/null
+/*
+ * Copyright 2009 Carlos Garnacho <carlosg@gnome.org>
+ * Copyright 2010 Kristian Rietveld <kris@gtk.org>
+ * Copyright 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#include <gdk/gdk.h>
+
+#include "gdkdeviceprivate.h"
+#include "gdkdisplayprivate.h"
+
+#include "gdkmacoscursor-private.h"
+#include "gdkmacosdevice.h"
+#include "gdkmacosdisplay-private.h"
+#include "gdkmacossurface-private.h"
+
+struct _GdkMacosDevice
+{
+ GdkDevice parent_instance;
+};
+
+struct _GdkMacosDeviceClass
+{
+ GdkDeviceClass parent_class;
+};
+
+G_DEFINE_TYPE (GdkMacosDevice, gdk_macos_device, GDK_TYPE_DEVICE)
+
+static void
+gdk_macos_device_set_surface_cursor (GdkDevice *device,
+ GdkSurface *surface,
+ GdkCursor *cursor)
+{
+ NSCursor *nscursor;
+
+ g_assert (GDK_IS_MACOS_DEVICE (device));
+ g_assert (GDK_IS_MACOS_SURFACE (surface));
+ g_assert (!cursor || GDK_IS_CURSOR (cursor));
+
+ nscursor = _gdk_macos_cursor_get_ns_cursor (cursor);
+
+ if (nscursor != NULL)
+ {
+ [nscursor set];
+ [nscursor release];
+ }
+}
+
+static GdkSurface *
+gdk_macos_device_surface_at_position (GdkDevice *device,
+ gdouble *win_x,
+ gdouble *win_y,
+ GdkModifierType *state)
+{
+ GdkMacosDisplay *display;
+ GdkMacosSurface *surface;
+ NSPoint point;
+ gint x;
+ gint y;
+
+ g_assert (GDK_IS_MACOS_DEVICE (device));
+ g_assert (win_x != NULL);
+ g_assert (win_y != NULL);
+
+ point = [NSEvent mouseLocation];
+ display = GDK_MACOS_DISPLAY (gdk_device_get_display (device));
+
+ if (state != NULL)
+ *state = (_gdk_macos_display_get_current_keyboard_modifiers (display) |
+ _gdk_macos_display_get_current_mouse_modifiers (display));
+
+ surface = _gdk_macos_display_get_surface_at_display_coords (display, point.x, point.y, &x, &y);
+
+ *win_x = x;
+ *win_y = y;
+
+ return GDK_SURFACE (surface);
+}
+
+static GdkGrabStatus
+gdk_macos_device_grab (GdkDevice *device,
+ GdkSurface *window,
+ gboolean owner_events,
+ GdkEventMask event_mask,
+ GdkSurface *confine_to,
+ GdkCursor *cursor,
+ guint32 time_)
+{
+ /* Should remain empty */
+ return GDK_GRAB_SUCCESS;
+}
+
+static void
+gdk_macos_device_ungrab (GdkDevice *device,
+ guint32 time_)
+{
+ GdkMacosDevice *self = (GdkMacosDevice *)device;
+ GdkDeviceGrabInfo *grab;
+ GdkDisplay *display;
+
+ g_assert (GDK_IS_MACOS_DEVICE (self));
+
+ display = gdk_device_get_display (device);
+ grab = _gdk_display_get_last_device_grab (display, device);
+
+ if (grab != NULL)
+ grab->serial_end = 0;
+
+ _gdk_display_device_grab_update (display, device, device, 0);
+}
+
+static void
+gdk_macos_device_get_state (GdkDevice *device,
+ GdkSurface *surface,
+ gdouble *axes,
+ GdkModifierType *mask)
+{
+ gdouble x_pos, y_pos;
+
+ g_assert (GDK_IS_MACOS_DEVICE (device));
+ g_assert (GDK_IS_MACOS_SURFACE (surface));
+
+ gdk_surface_get_device_position (surface, device, &x_pos, &y_pos, mask);
+
+ if (axes != NULL)
+ {
+ axes[0] = x_pos;
+ axes[1] = y_pos;
+ }
+}
+
+static void
+gdk_macos_device_query_state (GdkDevice *device,
+ GdkSurface *surface,
+ GdkSurface **child_surface,
+ gdouble *win_x,
+ gdouble *win_y,
+ GdkModifierType *mask)
+{
+ GdkDisplay *display;
+ NSPoint point;
+ int sx = 0;
+ int sy = 0;
+ int x_tmp;
+ int y_tmp;
+
+ g_assert (GDK_IS_MACOS_DEVICE (device));
+ g_assert (!surface || GDK_IS_MACOS_SURFACE (surface));
+
+ if (child_surface)
+ *child_surface = surface;
+
+ display = gdk_device_get_display (device);
+ point = [NSEvent mouseLocation];
+ _gdk_macos_display_from_display_coords (GDK_MACOS_DISPLAY (display),
+ point.x, point.y,
+ &x_tmp, &y_tmp);
+
+ if (surface)
+ _gdk_macos_surface_get_root_coords (GDK_MACOS_SURFACE (surface), &sx, &sy);
+
+ if (win_x)
+ *win_x = x_tmp - sx;
+
+ if (win_y)
+ *win_y = y_tmp - sy;
+
+ if (mask)
+ *mask = _gdk_macos_display_get_current_keyboard_modifiers (GDK_MACOS_DISPLAY (display)) |
+ _gdk_macos_display_get_current_mouse_modifiers (GDK_MACOS_DISPLAY (display));
+}
+
+static void
+gdk_macos_device_class_init (GdkMacosDeviceClass *klass)
+{
+ GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
+
+ device_class->get_state = gdk_macos_device_get_state;
+ device_class->grab = gdk_macos_device_grab;
+ device_class->query_state = gdk_macos_device_query_state;
+ device_class->set_surface_cursor = gdk_macos_device_set_surface_cursor;
+ device_class->surface_at_position = gdk_macos_device_surface_at_position;
+ device_class->ungrab = gdk_macos_device_ungrab;
+}
+
+static void
+gdk_macos_device_init (GdkMacosDevice *self)
+{
+ _gdk_device_add_axis (GDK_DEVICE (self), GDK_AXIS_X, 0, 0, 1);
+ _gdk_device_add_axis (GDK_DEVICE (self), GDK_AXIS_Y, 0, 0, 1);
+}
--- /dev/null
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef __GDK_MACOS_DEVICE_H__
+#define __GDK_MACOS_DEVICE_H__
+
+#if !defined (__GDKMACOS_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gdk/macos/gdkmacos.h> can be included directly."
+#endif
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GdkMacosDevice GdkMacosDevice;
+typedef struct _GdkMacosDeviceClass GdkMacosDeviceClass;
+
+#define GDK_TYPE_MACOS_DEVICE (gdk_macos_device_get_type())
+#define GDK_MACOS_DEVICE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_MACOS_DEVICE, GdkMacosDevice))
+#define GDK_IS_MACOS_DEVICE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MACOS_DEVICE))
+
+GDK_AVAILABLE_IN_ALL
+GType gdk_macos_device_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GDK_MACOS_DEVICE_H__ */
--- /dev/null
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef __GDK_MACOS_DISPLAY_PRIVATE_H__
+#define __GDK_MACOS_DISPLAY_PRIVATE_H__
+
+#include <AppKit/AppKit.h>
+
+#include "gdkdisplayprivate.h"
+
+#include "gdkmacosdisplay.h"
+#include "gdkmacoskeymap.h"
+#include "gdkmacossurface.h"
+
+G_BEGIN_DECLS
+
+struct _GdkMacosDisplay
+{
+ GdkDisplay parent_instance;
+
+ char *name;
+ GdkMacosKeymap *keymap;
+
+ /* An list of GdkMacosMonitor. The first instance is always the primary
+ * monitor. This contains the 0,0 coordinate in quartz coordinates, but may
+ * not be 0,0 in GDK coordinates.
+ */
+ GListStore *monitors;
+
+ /* A queue of surfaces that have been made "main" so that we can update the
+ * main status to the next surface when a window has lost main status (such
+ * as when destroyed). This uses the GdkMacosSurface main link.
+ */
+ GQueue main_surfaces;
+
+ /* A queue of surfaces sorted by their front-to-back ordering on the screen.
+ * This is updated occasionally when we know that the data we have cached
+ * has been invalidated. This uses the GdkMacosSurface.sorted link.
+ */
+ GQueue sorted_surfaces;
+
+ /* Our CVDisplayLink based GSource which we use to freeze/thaw the
+ * GdkFrameClock for the surface.
+ */
+ GSource *frame_source;
+
+ /* A queue of surfaces which we know are awaiting frames to be drawn. This
+ * uses the GdkMacosSurface.frame link.
+ */
+ GQueue awaiting_frames;
+
+ /* The surface that is receiving keyboard events */
+ GdkMacosSurface *keyboard_surface;
+
+ /* Used to translate from quartz coordinate space to GDK */
+ int width;
+ int height;
+ int min_x;
+ int min_y;
+ int max_x;
+ int max_y;
+};
+
+struct _GdkMacosDisplayClass
+{
+ GdkDisplayClass parent_class;
+};
+
+
+GdkDisplay *_gdk_macos_display_open (const gchar *display_name);
+int _gdk_macos_display_get_fd (GdkMacosDisplay *self);
+void _gdk_macos_display_queue_events (GdkMacosDisplay *self);
+void _gdk_macos_display_to_display_coords (GdkMacosDisplay *self,
+ int x,
+ int y,
+ int *out_x,
+ int *out_y);
+void _gdk_macos_display_from_display_coords (GdkMacosDisplay *self,
+ int x,
+ int y,
+ int *out_x,
+ int *out_y);
+NSScreen *_gdk_macos_display_get_screen_at_display_coords (GdkMacosDisplay *self,
+ int x,
+ int y);
+GdkMonitor *_gdk_macos_display_get_monitor_at_coords (GdkMacosDisplay *self,
+ int x,
+ int y);
+GdkMonitor *_gdk_macos_display_get_monitor_at_display_coords (GdkMacosDisplay *self,
+ int x,
+ int y);
+GdkEvent *_gdk_macos_display_translate (GdkMacosDisplay *self,
+ NSEvent *event);
+void _gdk_macos_display_break_all_grabs (GdkMacosDisplay *self,
+ guint32 time);
+GdkModifierType _gdk_macos_display_get_current_keyboard_modifiers (GdkMacosDisplay *self);
+GdkModifierType _gdk_macos_display_get_current_mouse_modifiers (GdkMacosDisplay *self);
+GdkMacosSurface *_gdk_macos_display_get_surface_at_display_coords (GdkMacosDisplay *self,
+ double x,
+ double y,
+ int *surface_x,
+ int *surface_y);
+void _gdk_macos_display_reload_monitors (GdkMacosDisplay *self);
+void _gdk_macos_display_surface_removed (GdkMacosDisplay *self,
+ GdkMacosSurface *surface);
+void _gdk_macos_display_add_frame_callback (GdkMacosDisplay *self,
+ GdkMacosSurface *surface);
+void _gdk_macos_display_remove_frame_callback (GdkMacosDisplay *self,
+ GdkMacosSurface *surface);
+void _gdk_macos_display_synthesize_motion (GdkMacosDisplay *self,
+ GdkMacosSurface *surface);
+NSWindow *_gdk_macos_display_find_native_under_pointer (GdkMacosDisplay *self,
+ int *x,
+ int *y);
+gboolean _gdk_macos_display_get_setting (GdkMacosDisplay *self,
+ const gchar *setting,
+ GValue *value);
+void _gdk_macos_display_reload_settings (GdkMacosDisplay *self);
+void _gdk_macos_display_surface_resigned_main (GdkMacosDisplay *self,
+ GdkMacosSurface *surface);
+void _gdk_macos_display_surface_became_main (GdkMacosDisplay *self,
+ GdkMacosSurface *surface);
+void _gdk_macos_display_surface_resigned_key (GdkMacosDisplay *self,
+ GdkMacosSurface *surface);
+void _gdk_macos_display_surface_became_key (GdkMacosDisplay *self,
+ GdkMacosSurface *surface);
+int _gdk_macos_display_get_nominal_refresh_rate (GdkMacosDisplay *self);
+void _gdk_macos_display_clear_sorting (GdkMacosDisplay *self);
+const GList *_gdk_macos_display_get_surfaces (GdkMacosDisplay *self);
+void _gdk_macos_display_send_button_event (GdkMacosDisplay *self,
+ NSEvent *nsevent);
+void _gdk_macos_display_warp_pointer (GdkMacosDisplay *self,
+ int x,
+ int y);
+
+G_END_DECLS
+
+#endif /* __GDK_MACOS_DISPLAY_PRIVATE_H__ */
--- /dev/null
+/*
+ * Copyright © 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Copyright © 1998-2002 Tor Lillqvist
+ * Copyright © 2005-2008 Imendio AB
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#include <AppKit/AppKit.h>
+
+#include "gdkdisplayprivate.h"
+
+#include "gdkmacosdisplay-private.h"
+#include "gdkmacosutils-private.h"
+
+typedef struct
+{
+ const char *font_name;
+ int xft_dpi;
+ int double_click_time;
+ int cursor_blink_timeout;
+ guint enable_animations : 1;
+ guint shell_shows_desktop : 1;
+ guint shell_shows_menubar : 1;
+ guint primary_button_warps_slider : 1;
+} GdkMacosSettings;
+
+static GdkMacosSettings current_settings;
+static gboolean current_settings_initialized;
+
+static void
+_gdk_macos_settings_load (GdkMacosSettings *settings)
+{
+ GDK_BEGIN_MACOS_ALLOC_POOL;
+
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+ NSString *name;
+ NSInteger ival;
+ float fval;
+ char *str;
+ int pt_size;
+
+ g_assert (settings != NULL);
+
+ settings->shell_shows_desktop = TRUE;
+ settings->shell_shows_menubar = TRUE;
+ settings->enable_animations = TRUE;
+ settings->xft_dpi = 72 * 1024;
+
+ ival = [defaults integerForKey:@"NSTextInsertionPointBlinkPeriod"];
+ if (ival > 0)
+ settings->cursor_blink_timeout = ival;
+ else
+ settings->cursor_blink_timeout = 1000;
+
+ settings->primary_button_warps_slider =
+ [[NSUserDefaults standardUserDefaults] boolForKey:@"AppleScrollerPagingBehavior"] == YES;
+
+ fval = [defaults floatForKey:@"com.apple.mouse.doubleClickThreshold"];
+ if (fval == 0.0)
+ fval = 0.5;
+ settings->double_click_time = fval * 1000;
+
+ name = [[NSFont systemFontOfSize:0] familyName];
+ pt_size = (gint)[[NSFont userFontOfSize:0] pointSize];
+ /* Let's try to use the "views" font size (12pt) by default. This is
+ * used for lists/text/other "content" which is the largest parts of
+ * apps, using the "regular control" size (13pt) looks a bit out of
+ * place. We might have to tweak this.
+ *
+ * The size has to be hardcoded as there doesn't seem to be a way to
+ * get the views font size programmatically.
+ */
+ str = g_strdup_printf ("%s %d", [name UTF8String], pt_size);
+ settings->font_name = g_intern_string (str);
+ g_free (str);
+
+ GDK_END_MACOS_ALLOC_POOL;
+}
+
+gboolean
+_gdk_macos_display_get_setting (GdkMacosDisplay *self,
+ const gchar *setting,
+ GValue *value)
+{
+ GDK_BEGIN_MACOS_ALLOC_POOL;
+
+ gboolean ret = FALSE;
+
+ g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (self), FALSE);
+ g_return_val_if_fail (setting != NULL, FALSE);
+ g_return_val_if_fail (value != NULL, FALSE);
+
+ if (!current_settings_initialized)
+ {
+ _gdk_macos_settings_load (¤t_settings);
+ current_settings_initialized = TRUE;
+ }
+
+ if (FALSE) {}
+ else if (strcmp (setting, "gtk-enable-animations") == 0)
+ {
+ g_value_set_boolean (value, current_settings.enable_animations);
+ ret = TRUE;
+ }
+ else if (strcmp (setting, "gtk-xft-dpi") == 0)
+ {
+ g_value_set_int (value, current_settings.xft_dpi);
+ ret = TRUE;
+ }
+ else if (strcmp (setting, "gtk-cursor-blink-timeout") == 0)
+ {
+ g_value_set_int (value, current_settings.cursor_blink_timeout);
+ ret = TRUE;
+ }
+ else if (strcmp (setting, "gtk-double-click-time") == 0)
+ {
+ g_value_set_int (value, current_settings.double_click_time);
+ ret = TRUE;
+ }
+ else if (strcmp (setting, "gtk-font-name") == 0)
+ {
+ g_value_set_static_string (value, current_settings.font_name);
+ ret = TRUE;
+ }
+ else if (strcmp (setting, "gtk-primary-button-warps-slider") == 0)
+ {
+ g_value_set_boolean (value, current_settings.primary_button_warps_slider);
+ ret = TRUE;
+ }
+ else if (strcmp (setting, "gtk-shell-shows-desktop") == 0)
+ {
+ g_value_set_boolean (value, current_settings.shell_shows_desktop);
+ ret = TRUE;
+ }
+ else if (strcmp (setting, "gtk-shell-shows-menubar") == 0)
+ {
+ g_value_set_boolean (value, current_settings.shell_shows_menubar);
+ ret = TRUE;
+ }
+
+ GDK_END_MACOS_ALLOC_POOL;
+
+ return ret;
+}
+
+void
+_gdk_macos_display_reload_settings (GdkMacosDisplay *self)
+{
+ GdkMacosSettings old_settings;
+
+ g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
+
+ old_settings = current_settings;
+ _gdk_macos_settings_load (¤t_settings);
+ current_settings_initialized = TRUE;
+
+ if (old_settings.xft_dpi != current_settings.xft_dpi)
+ gdk_display_setting_changed (GDK_DISPLAY (self), "gtk-xft-dpi");
+
+ if (old_settings.double_click_time != current_settings.double_click_time)
+ gdk_display_setting_changed (GDK_DISPLAY (self), "gtk-double-click-time");
+
+ if (old_settings.enable_animations != current_settings.enable_animations)
+ gdk_display_setting_changed (GDK_DISPLAY (self), "gtk-enable-animations");
+
+ if (old_settings.font_name != current_settings.font_name)
+ gdk_display_setting_changed (GDK_DISPLAY (self), "gtk-font-name");
+
+ if (old_settings.primary_button_warps_slider != current_settings.primary_button_warps_slider)
+ gdk_display_setting_changed (GDK_DISPLAY (self), "gtk-primary-button-warps-slider");
+
+ if (old_settings.shell_shows_menubar != current_settings.shell_shows_menubar)
+ gdk_display_setting_changed (GDK_DISPLAY (self), "gtk-shell-shows-menubar");
+
+ if (old_settings.shell_shows_desktop != current_settings.shell_shows_desktop)
+ gdk_display_setting_changed (GDK_DISPLAY (self), "gtk-shell-shows-desktop");
+}
--- /dev/null
+/*
+ * Copyright 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Copyright 1998-2002 Tor Lillqvist
+ * Copyright 2005-2008 Imendio AB
+ * Copyright 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#import "GdkMacosWindow.h"
+#import "GdkMacosBaseView.h"
+
+#include "gdkmacosdisplay-private.h"
+#include "gdkmacoskeymap-private.h"
+#include "gdkmacossurface-private.h"
+
+#define GDK_MOD2_MASK (1 << 4)
+#define GRIP_WIDTH 15
+#define GRIP_HEIGHT 15
+#define GDK_LION_RESIZE 5
+
+static gboolean
+test_resize (NSEvent *event,
+ GdkMacosSurface *surface,
+ int x,
+ int y)
+{
+ NSWindow *window;
+
+ g_assert (event != NULL);
+ g_assert (GDK_IS_MACOS_SURFACE (surface));
+
+ window = _gdk_macos_surface_get_native (surface);
+
+ /* Resizing from the resize indicator only begins if an NSLeftMouseButton
+ * event is received in the resizing area.
+ */
+ if ([event type] == NSEventTypeLeftMouseDown &&
+ [window showsResizeIndicator])
+ {
+ NSRect frame;
+
+ /* If the resize indicator is visible and the event is in the lower
+ * right 15x15 corner, we leave these events to Cocoa as to be
+ * handled as resize events. Applications may have widgets in this
+ * area. These will most likely be larger than 15x15 and for scroll
+ * bars there are also other means to move the scroll bar. Since
+ * the resize indicator is the only way of resizing windows on Mac
+ * OS, it is too important to not make functional.
+ */
+ frame = [[window contentView] bounds];
+ if (x > frame.size.width - GRIP_WIDTH &&
+ x < frame.size.width &&
+ y > frame.size.height - GRIP_HEIGHT &&
+ y < frame.size.height)
+ return TRUE;
+ }
+
+ /* If we're on Lion and within 5 pixels of an edge, then assume that the
+ * user wants to resize, and return NULL to let Quartz get on with it.
+ * We check the selector isRestorable to see if we're on 10.7. This
+ * extra check is in case the user starts dragging before GDK recognizes
+ * the grab.
+ *
+ * We perform this check for a button press of all buttons, because we
+ * do receive, for instance, a right mouse down event for a GDK surface
+ * for x-coordinate range [-3, 0], but we do not want to forward this
+ * into GDK. Forwarding such events into GDK will confuse the pointer
+ * window finding code, because there are no GdkSurfaces present in
+ * the range [-3, 0].
+ */
+ if (([event type] == NSEventTypeLeftMouseDown ||
+ [event type] == NSEventTypeRightMouseDown ||
+ [event type] == NSEventTypeOtherMouseDown))
+ {
+ if (x < GDK_LION_RESIZE ||
+ x > GDK_SURFACE (surface)->width - GDK_LION_RESIZE ||
+ y > GDK_SURFACE (surface)->height - GDK_LION_RESIZE)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static guint32
+get_time_from_ns_event (NSEvent *event)
+{
+ double time = [event timestamp];
+ /* cast via double->uint64 conversion to make sure that it is
+ * wrapped on 32-bit machines when it overflows
+ */
+ return (guint32) (guint64) (time * 1000.0);
+}
+
+static int
+get_mouse_button_from_ns_event (NSEvent *event)
+{
+ NSInteger button = [event buttonNumber];
+
+ switch (button)
+ {
+ case 0:
+ return 1;
+ case 1:
+ return 3;
+ case 2:
+ return 2;
+ default:
+ return button + 1;
+ }
+}
+
+static GdkModifierType
+get_mouse_button_modifiers_from_ns_buttons (NSUInteger nsbuttons)
+{
+ GdkModifierType modifiers = 0;
+
+ if (nsbuttons & (1 << 0))
+ modifiers |= GDK_BUTTON1_MASK;
+ if (nsbuttons & (1 << 1))
+ modifiers |= GDK_BUTTON3_MASK;
+ if (nsbuttons & (1 << 2))
+ modifiers |= GDK_BUTTON2_MASK;
+ if (nsbuttons & (1 << 3))
+ modifiers |= GDK_BUTTON4_MASK;
+ if (nsbuttons & (1 << 4))
+ modifiers |= GDK_BUTTON5_MASK;
+
+ return modifiers;
+}
+
+static GdkModifierType
+get_mouse_button_modifiers_from_ns_event (NSEvent *event)
+{
+ GdkModifierType state = 0;
+ int button;
+
+ /* This maps buttons 1 to 5 to GDK_BUTTON[1-5]_MASK */
+ button = get_mouse_button_from_ns_event (event);
+ if (button >= 1 && button <= 5)
+ state = (1 << (button + 7));
+
+ return state;
+}
+
+static GdkModifierType
+get_keyboard_modifiers_from_ns_flags (NSUInteger nsflags)
+{
+ GdkModifierType modifiers = 0;
+
+ if (nsflags & NSEventModifierFlagCapsLock)
+ modifiers |= GDK_LOCK_MASK;
+ if (nsflags & NSEventModifierFlagShift)
+ modifiers |= GDK_SHIFT_MASK;
+ if (nsflags & NSEventModifierFlagControl)
+ modifiers |= GDK_CONTROL_MASK;
+ if (nsflags & NSEventModifierFlagOption)
+ modifiers |= GDK_ALT_MASK;
+ if (nsflags & NSEventModifierFlagCommand)
+ modifiers |= GDK_MOD2_MASK;
+
+ return modifiers;
+}
+
+static GdkModifierType
+get_keyboard_modifiers_from_ns_event (NSEvent *nsevent)
+{
+ return get_keyboard_modifiers_from_ns_flags ([nsevent modifierFlags]);
+}
+
+GdkModifierType
+_gdk_macos_display_get_current_mouse_modifiers (GdkMacosDisplay *self)
+{
+ return get_mouse_button_modifiers_from_ns_buttons ([NSEvent pressedMouseButtons]);
+}
+
+GdkModifierType
+_gdk_macos_display_get_current_keyboard_modifiers (GdkMacosDisplay *self)
+{
+ return get_keyboard_modifiers_from_ns_flags ([NSEvent modifierFlags]);
+}
+
+static GdkEvent *
+fill_button_event (GdkMacosDisplay *display,
+ GdkMacosSurface *surface,
+ NSEvent *nsevent,
+ int x,
+ int y)
+{
+ GdkSeat *seat;
+ GdkEventType type;
+ GdkModifierType state;
+
+ g_assert (GDK_IS_MACOS_DISPLAY (display));
+ g_assert (GDK_IS_MACOS_SURFACE (surface));
+
+ /* Ignore button events outside the window coords */
+ if (x < 0 || x > GDK_SURFACE (surface)->width ||
+ y < 0 || y > GDK_SURFACE (surface)->height)
+ return NULL;
+
+ seat = gdk_display_get_default_seat (GDK_DISPLAY (display));
+ state = get_keyboard_modifiers_from_ns_event (nsevent) |
+ _gdk_macos_display_get_current_mouse_modifiers (display);
+
+ switch ((int)[nsevent type])
+ {
+ case NSEventTypeLeftMouseDown:
+ case NSEventTypeRightMouseDown:
+ case NSEventTypeOtherMouseDown:
+ type = GDK_BUTTON_PRESS;
+ state &= ~get_mouse_button_modifiers_from_ns_event (nsevent);
+ break;
+
+ case NSEventTypeLeftMouseUp:
+ case NSEventTypeRightMouseUp:
+ case NSEventTypeOtherMouseUp:
+ type = GDK_BUTTON_RELEASE;
+ state |= get_mouse_button_modifiers_from_ns_event (nsevent);
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ return gdk_button_event_new (type,
+ GDK_SURFACE (surface),
+ gdk_seat_get_pointer (seat),
+ NULL,
+ NULL,
+ get_time_from_ns_event (nsevent),
+ state,
+ get_mouse_button_from_ns_event (nsevent),
+ x,
+ y,
+ NULL);
+}
+
+static GdkEvent *
+synthesize_crossing_event (GdkMacosDisplay *display,
+ GdkMacosSurface *surface,
+ NSEvent *nsevent,
+ int x,
+ int y)
+{
+ GdkEventType event_type;
+ GdkModifierType state;
+ GdkSeat *seat;
+
+ switch ((int)[nsevent type])
+ {
+ case NSEventTypeMouseEntered:
+ event_type = GDK_ENTER_NOTIFY;
+ break;
+
+ case NSEventTypeMouseExited:
+ event_type = GDK_LEAVE_NOTIFY;
+ break;
+
+ default:
+ g_return_val_if_reached (NULL);
+ }
+
+ state = get_keyboard_modifiers_from_ns_event (nsevent) |
+ _gdk_macos_display_get_current_mouse_modifiers (display);
+ seat = gdk_display_get_default_seat (GDK_DISPLAY (display));
+
+ return gdk_crossing_event_new (event_type,
+ GDK_SURFACE (surface),
+ gdk_seat_get_pointer (seat),
+ NULL,
+ get_time_from_ns_event (nsevent),
+ state,
+ x,
+ y,
+ GDK_CROSSING_NORMAL,
+ GDK_NOTIFY_NONLINEAR);
+}
+
+static inline guint
+get_group_from_ns_event (NSEvent *nsevent)
+{
+ return ([nsevent modifierFlags] & NSEventModifierFlagOption) ? 1 : 0;
+}
+
+static void
+add_virtual_modifiers (GdkModifierType *state)
+{
+ if (*state & GDK_MOD2_MASK)
+ *state |= GDK_META_MASK;
+}
+
+static GdkEvent *
+fill_key_event (GdkMacosDisplay *display,
+ GdkMacosSurface *surface,
+ NSEvent *nsevent,
+ GdkEventType type)
+{
+ GdkTranslatedKey translated = {0};
+ GdkTranslatedKey no_lock = {0};
+ GdkModifierType consumed;
+ GdkModifierType state;
+ GdkKeymap *keymap;
+ gboolean is_modifier;
+ GdkSeat *seat;
+ guint keycode;
+ guint keyval;
+ guint group;
+ int layout;
+ int level;
+
+ g_assert (GDK_IS_MACOS_DISPLAY (display));
+ g_assert (GDK_IS_MACOS_SURFACE (surface));
+ g_assert (nsevent != NULL);
+
+ seat = gdk_display_get_default_seat (GDK_DISPLAY (display));
+ keymap = gdk_display_get_keymap (GDK_DISPLAY (display));
+ keycode = [nsevent keyCode];
+ keyval = GDK_KEY_VoidSymbol;
+ state = get_keyboard_modifiers_from_ns_event (nsevent);
+ group = get_group_from_ns_event (nsevent);
+ is_modifier = _gdk_macos_keymap_is_modifier (keycode);
+
+ gdk_keymap_translate_keyboard_state (keymap, keycode, state, group,
+ &keyval, &layout, &level, &consumed);
+
+ /* If the key press is a modifier, the state should include the mask for
+ * that modifier but only for releases, not presses. This matches the
+ * X11 backend behavior.
+ */
+ if (is_modifier)
+ {
+ guint mask = 0;
+
+ switch (keyval)
+ {
+ case GDK_KEY_Meta_R:
+ case GDK_KEY_Meta_L:
+ mask = GDK_MOD2_MASK;
+ break;
+ case GDK_KEY_Shift_R:
+ case GDK_KEY_Shift_L:
+ mask = GDK_SHIFT_MASK;
+ break;
+ case GDK_KEY_Caps_Lock:
+ mask = GDK_LOCK_MASK;
+ break;
+ case GDK_KEY_Alt_R:
+ case GDK_KEY_Alt_L:
+ mask = GDK_ALT_MASK;
+ break;
+ case GDK_KEY_Control_R:
+ case GDK_KEY_Control_L:
+ mask = GDK_CONTROL_MASK;
+ break;
+ default:
+ mask = 0;
+ }
+
+ if (type == GDK_KEY_PRESS)
+ state &= ~mask;
+ else if (type == GDK_KEY_RELEASE)
+ state |= mask;
+ }
+
+ state |= _gdk_macos_display_get_current_mouse_modifiers (display);
+ add_virtual_modifiers (&state);
+
+ translated.keyval = keyval;
+ translated.consumed = consumed;
+ translated.layout = layout;
+ translated.level = level;
+
+ if (state & GDK_LOCK_MASK)
+ {
+ gdk_keymap_translate_keyboard_state (keymap,
+ keycode,
+ state & ~GDK_LOCK_MASK,
+ group,
+ &keyval,
+ &layout,
+ &level,
+ &consumed);
+
+ no_lock.keyval = keycode;
+ no_lock.consumed = consumed;
+ no_lock.layout = layout;
+ no_lock.level = level;
+ }
+ else
+ {
+ no_lock = translated;
+ }
+
+ return gdk_key_event_new (type,
+ GDK_SURFACE (surface),
+ gdk_seat_get_keyboard (seat),
+ NULL,
+ get_time_from_ns_event (nsevent),
+ [nsevent keyCode],
+ state,
+ is_modifier,
+ &translated,
+ &no_lock);
+}
+
+static GdkEvent *
+fill_pinch_event (GdkMacosDisplay *display,
+ GdkMacosSurface *surface,
+ NSEvent *nsevent,
+ int x,
+ int y)
+{
+ static double last_scale = 1.0;
+ static enum {
+ FP_STATE_IDLE,
+ FP_STATE_UPDATE
+ } last_state = FP_STATE_IDLE;
+ GdkSeat *seat;
+ GdkTouchpadGesturePhase phase;
+ gdouble angle_delta = 0.0;
+
+ g_assert (GDK_IS_MACOS_DISPLAY (display));
+ g_assert (GDK_IS_MACOS_SURFACE (surface));
+
+ /* fill_pinch_event handles the conversion from the two OSX gesture events
+ * NSEventTypeMagnfiy and NSEventTypeRotate to the GDK_TOUCHPAD_PINCH event.
+ * The normal behavior of the OSX events is that they produce as sequence of
+ * 1 x NSEventPhaseBegan,
+ * n x NSEventPhaseChanged,
+ * 1 x NSEventPhaseEnded
+ * This can happen for both the Magnify and the Rotate events independently.
+ * As both events are summarized in one GDK_TOUCHPAD_PINCH event sequence, a
+ * little state machine handles the case of two NSEventPhaseBegan events in
+ * a sequence, e.g. Magnify(Began), Magnify(Changed)..., Rotate(Began)...
+ * such that PINCH(STARTED), PINCH(UPDATE).... will not show a second
+ * PINCH(STARTED) event.
+ */
+
+ switch ((int)[nsevent phase])
+ {
+ case NSEventPhaseBegan:
+ switch (last_state)
+ {
+ case FP_STATE_IDLE:
+ phase = GDK_TOUCHPAD_GESTURE_PHASE_BEGIN;
+ last_state = FP_STATE_UPDATE;
+ last_scale = 1.0;
+ break;
+ case FP_STATE_UPDATE:
+ /* We have already received a PhaseBegan event but no PhaseEnded
+ event. This can happen, e.g. Magnify(Began), Magnify(Change)...
+ Rotate(Began), Rotate (Change),...., Magnify(End) Rotate(End)
+ */
+ phase = GDK_TOUCHPAD_GESTURE_PHASE_UPDATE;
+ break;
+ }
+ break;
+
+ case NSEventPhaseChanged:
+ phase = GDK_TOUCHPAD_GESTURE_PHASE_UPDATE;
+ break;
+
+ case NSEventPhaseEnded:
+ phase = GDK_TOUCHPAD_GESTURE_PHASE_END;
+ switch (last_state)
+ {
+ case FP_STATE_IDLE:
+ /* We are idle but have received a second PhaseEnded event.
+ This can happen because we have Magnify and Rotate OSX
+ event sequences. We just send a second end GDK_PHASE_END.
+ */
+ break;
+ case FP_STATE_UPDATE:
+ last_state = FP_STATE_IDLE;
+ break;
+ }
+ break;
+
+ case NSEventPhaseCancelled:
+ phase = GDK_TOUCHPAD_GESTURE_PHASE_CANCEL;
+ last_state = FP_STATE_IDLE;
+ break;
+
+ case NSEventPhaseMayBegin:
+ case NSEventPhaseStationary:
+ phase = GDK_TOUCHPAD_GESTURE_PHASE_CANCEL;
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ switch ((int)[nsevent type])
+ {
+ case NSEventTypeMagnify:
+ last_scale *= [nsevent magnification] + 1.0;
+ angle_delta = 0.0;
+ break;
+
+ case NSEventTypeRotate:
+ angle_delta = - [nsevent rotation] * G_PI / 180.0;
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ seat = gdk_display_get_default_seat (GDK_DISPLAY (display));
+
+ return gdk_touchpad_event_new_pinch (GDK_SURFACE (surface),
+ gdk_seat_get_pointer (seat),
+ NULL,
+ get_time_from_ns_event (nsevent),
+ get_keyboard_modifiers_from_ns_event (nsevent),
+ phase,
+ x,
+ y,
+ 2,
+ 0.0,
+ 0.0,
+ last_scale,
+ angle_delta);
+
+}
+
+static gboolean
+is_motion_event (NSEventType event_type)
+{
+ return (event_type == NSEventTypeLeftMouseDragged ||
+ event_type == NSEventTypeRightMouseDragged ||
+ event_type == NSEventTypeOtherMouseDragged ||
+ event_type == NSEventTypeMouseMoved);
+}
+
+static GdkEvent *
+fill_motion_event (GdkMacosDisplay *display,
+ GdkMacosSurface *surface,
+ NSEvent *nsevent,
+ int x,
+ int y)
+{
+ GdkSeat *seat;
+ GdkModifierType state;
+
+ g_assert (GDK_IS_MACOS_SURFACE (surface));
+ g_assert (nsevent != NULL);
+ g_assert (is_motion_event ([nsevent type]));
+
+ seat = gdk_display_get_default_seat (GDK_DISPLAY (display));
+ state = get_keyboard_modifiers_from_ns_event (nsevent) |
+ _gdk_macos_display_get_current_mouse_modifiers (display);
+
+ return gdk_motion_event_new (GDK_SURFACE (surface),
+ gdk_seat_get_pointer (seat),
+ NULL,
+ NULL,
+ get_time_from_ns_event (nsevent),
+ state,
+ x,
+ y,
+ NULL);
+}
+
+static GdkEvent *
+fill_scroll_event (GdkMacosDisplay *self,
+ GdkMacosSurface *surface,
+ NSEvent *nsevent,
+ int x,
+ int y)
+{
+ GdkScrollDirection direction = 0;
+ GdkModifierType state;
+ GdkDevice *pointer;
+ GdkEvent *ret = NULL;
+ GdkSeat *seat;
+ gdouble dx;
+ gdouble dy;
+
+ g_assert (GDK_IS_MACOS_SURFACE (surface));
+ g_assert (nsevent != NULL);
+
+ seat = gdk_display_get_default_seat (GDK_DISPLAY (self));
+ pointer = gdk_seat_get_pointer (seat);
+ state = _gdk_macos_display_get_current_mouse_modifiers (self) |
+ _gdk_macos_display_get_current_keyboard_modifiers (self);
+
+ dx = [nsevent deltaX];
+ dy = [nsevent deltaY];
+
+ if ([nsevent hasPreciseScrollingDeltas])
+ {
+ gdouble sx;
+ gdouble sy;
+
+ /*
+ * TODO: We probably need another event type for the
+ * high precision scroll events since sx and dy
+ * are in a unit we don't quite support. For now,
+ * to slow it down multiply by .1.
+ */
+
+ sx = [nsevent scrollingDeltaX] * .1;
+ sy = [nsevent scrollingDeltaY] * .1;
+
+ if (sx != 0.0 || dx != 0.0)
+ ret = gdk_scroll_event_new (GDK_SURFACE (surface),
+ pointer,
+ NULL,
+ NULL,
+ get_time_from_ns_event (nsevent),
+ state,
+ -sx,
+ -sy,
+ FALSE);
+
+ /* Fall through for scroll emulation */
+ }
+
+ if (dy != 0.0)
+ {
+ if (dy < 0.0)
+ direction = GDK_SCROLL_DOWN;
+ else
+ direction = GDK_SCROLL_UP;
+
+ dx = 0.0;
+ }
+ else if (dx != 0.0)
+ {
+ if (dx < 0.0)
+ direction = GDK_SCROLL_RIGHT;
+ else
+ direction = GDK_SCROLL_LEFT;
+
+ dy = 0.0;
+ }
+
+ if (dx != 0.0 || dy != 0.0)
+ {
+ if ([nsevent hasPreciseScrollingDeltas])
+ {
+ GdkEvent *emulated;
+
+ emulated = gdk_scroll_event_new_discrete (GDK_SURFACE (surface),
+ pointer,
+ NULL,
+ NULL,
+ get_time_from_ns_event (nsevent),
+ state,
+ direction,
+ TRUE);
+ _gdk_event_queue_append (GDK_DISPLAY (self), emulated);
+ }
+ else
+ {
+ g_assert (ret == NULL);
+
+ ret = gdk_scroll_event_new (GDK_SURFACE (surface),
+ pointer,
+ NULL,
+ NULL,
+ get_time_from_ns_event (nsevent),
+ state,
+ dx,
+ dy,
+ FALSE);
+ }
+ }
+
+ return g_steal_pointer (&ret);
+}
+
+static gboolean
+is_mouse_button_press_event (NSEventType type)
+{
+ switch ((int)type)
+ {
+ case NSEventTypeLeftMouseDown:
+ case NSEventTypeRightMouseDown:
+ case NSEventTypeOtherMouseDown:
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+}
+
+static void
+get_surface_point_from_screen_point (GdkSurface *surface,
+ NSPoint screen_point,
+ int *x,
+ int *y)
+{
+ NSWindow *nswindow;
+ NSPoint point;
+
+ nswindow = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (surface));
+ point = [nswindow convertPointFromScreen:screen_point];
+
+ *x = point.x;
+ *y = surface->height - point.y;
+}
+
+static GdkSurface *
+find_surface_under_pointer (GdkMacosDisplay *self,
+ NSPoint screen_point,
+ int *x,
+ int *y)
+{
+ GdkPointerSurfaceInfo *info;
+ GdkSurface *surface;
+ GdkSeat *seat;
+ int x_tmp, y_tmp;
+
+ seat = gdk_display_get_default_seat (GDK_DISPLAY (self));
+ info = _gdk_display_get_pointer_info (GDK_DISPLAY (self),
+ gdk_seat_get_pointer (seat));
+ surface = info->surface_under_pointer;
+
+ if (surface == NULL)
+ {
+ GdkMacosSurface *found;
+
+ found = _gdk_macos_display_get_surface_at_display_coords (self,
+ screen_point.x,
+ screen_point.y,
+ &x_tmp, &y_tmp);
+
+ if (found)
+ {
+ surface = GDK_SURFACE (found);
+ info->surface_under_pointer = g_object_ref (surface);
+ }
+ }
+
+ if (surface)
+ {
+ _gdk_macos_display_from_display_coords (self,
+ screen_point.x,
+ screen_point.y,
+ &x_tmp, &y_tmp);
+ *x = x_tmp - GDK_MACOS_SURFACE (surface)->root_x;
+ *y = y_tmp - GDK_MACOS_SURFACE (surface)->root_y;
+ /* If the coordinates are out of window bounds, this surface is not
+ * under the pointer and we thus return NULL. This can occur when
+ * surface under pointer has not yet been updated due to a very recent
+ * window resize. Alternatively, we should no longer be relying on
+ * the surface_under_pointer value which is maintained in gdkwindow.c.
+ */
+ if (*x < 0 || *y < 0 || *x >= surface->width || *y >= surface->height)
+ return NULL;
+ }
+
+ return surface;
+}
+
+static GdkSurface *
+get_surface_from_ns_event (GdkMacosDisplay *self,
+ NSEvent *nsevent,
+ NSPoint *screen_point,
+ int *x,
+ int *y)
+{
+ GdkSurface *surface = NULL;
+ NSWindow *nswindow = [nsevent window];
+
+ if (nswindow)
+ {
+ GdkMacosBaseView *view;
+ NSPoint point, view_point;
+ NSRect view_frame;
+
+ view = (GdkMacosBaseView *)[nswindow contentView];
+ surface = GDK_SURFACE ([view gdkSurface]);
+
+ point = [nsevent locationInWindow];
+ view_point = [view convertPoint:point fromView:nil];
+ view_frame = [view frame];
+
+ /* NSEvents come in with a window set, but with window coordinates
+ * out of window bounds. For e.g. moved events this is fine, we use
+ * this information to properly handle enter/leave notify and motion
+ * events. For mouse button press/release, we want to avoid forwarding
+ * these events however, because the window they relate to is not the
+ * window set in the event. This situation appears to occur when button
+ * presses come in just before (or just after?) a window is resized and
+ * also when a button press occurs on the OS X window titlebar.
+ *
+ * By setting surface to NULL, we do another attempt to get the right
+ * surface window below.
+ */
+ if (is_mouse_button_press_event ([nsevent type]) &&
+ (view_point.x < view_frame.origin.x ||
+ view_point.x >= view_frame.origin.x + view_frame.size.width ||
+ view_point.y < view_frame.origin.y ||
+ view_point.y >= view_frame.origin.y + view_frame.size.height))
+ {
+ NSRect windowRect = [nswindow frame];
+
+ surface = NULL;
+
+ /* This is a hack for button presses to break all grabs. E.g. if
+ * a menu is open and one clicks on the title bar (or anywhere
+ * out of window bounds), we really want to pop down the menu (by
+ * breaking the grabs) before OS X handles the action of the title
+ * bar button.
+ *
+ * Because we cannot ingest this event into GDK, we have to do it
+ * here, not very nice.
+ */
+ _gdk_macos_display_break_all_grabs (self, get_time_from_ns_event (nsevent));
+
+ /* If the X,Y is on the frame itself, then we don't want to discover
+ * the surface under the pointer at all so that we let OS X handle
+ * it instead. We add padding to include resize operations too.
+ */
+ windowRect.origin.x = -GDK_LION_RESIZE;
+ windowRect.origin.y = -GDK_LION_RESIZE;
+ windowRect.size.width += (2 * GDK_LION_RESIZE);
+ windowRect.size.height += (2 * GDK_LION_RESIZE);
+ if (NSPointInRect (point, windowRect))
+ return NULL;
+ }
+ else
+ {
+ *screen_point = [(GdkMacosWindow *)[nsevent window] convertPointToScreen:point];
+ *x = point.x;
+ *y = surface->height - point.y;
+ }
+ }
+
+ if (!surface)
+ {
+ /* Fallback used when no NSSurface set. This happens e.g. when
+ * we allow motion events without a window set in gdk_event_translate()
+ * that occur immediately after the main menu bar was clicked/used.
+ * This fallback will not return coordinates contained in a window's
+ * titlebar.
+ */
+ *screen_point = [NSEvent mouseLocation];
+ surface = find_surface_under_pointer (self, *screen_point, x, y);
+ }
+
+ return surface;
+}
+
+static GdkMacosSurface *
+find_surface_for_keyboard_event (NSEvent *nsevent)
+{
+ GdkMacosBaseView *view = (GdkMacosBaseView *)[[nsevent window] contentView];
+ GdkSurface *surface = GDK_SURFACE ([view gdkSurface]);
+ GdkDisplay *display = gdk_surface_get_display (surface);
+ GdkSeat *seat = gdk_display_get_default_seat (display);
+ GdkDevice *device = gdk_seat_get_keyboard (seat);
+ GdkDeviceGrabInfo *grab = _gdk_display_get_last_device_grab (display, device);
+
+ if (grab && grab->surface && !grab->owner_events)
+ return GDK_MACOS_SURFACE (grab->surface);
+
+ return GDK_MACOS_SURFACE (surface);
+}
+
+static GdkMacosSurface *
+find_surface_for_mouse_event (GdkMacosDisplay *self,
+ NSEvent *nsevent,
+ int *x,
+ int *y)
+{
+ NSPoint point;
+ NSEventType event_type;
+ GdkSurface *surface;
+ GdkDisplay *display;
+ GdkDevice *pointer;
+ GdkDeviceGrabInfo *grab;
+ GdkSeat *seat;
+
+ surface = get_surface_from_ns_event (self, nsevent, &point, x, y);
+ display = gdk_surface_get_display (surface);
+ seat = gdk_display_get_default_seat (GDK_DISPLAY (self));
+ pointer = gdk_seat_get_pointer (seat);
+
+ event_type = [nsevent type];
+
+ /* From the docs for XGrabPointer:
+ *
+ * If owner_events is True and if a generated pointer event
+ * would normally be reported to this client, it is reported
+ * as usual. Otherwise, the event is reported with respect to
+ * the grab_window and is reported only if selected by
+ * event_mask. For either value of owner_events, unreported
+ * events are discarded.
+ */
+ if ((grab = _gdk_display_get_last_device_grab (display, pointer)))
+ {
+ if (grab->owner_events)
+ {
+ /* For owner events, we need to use the surface under the
+ * pointer, not the window from the NSEvent, since that is
+ * reported with respect to the key window, which could be
+ * wrong.
+ */
+ GdkSurface *surface_under_pointer;
+ int x_tmp, y_tmp;
+
+ surface_under_pointer = find_surface_under_pointer (self, point, &x_tmp, &y_tmp);
+ if (surface_under_pointer)
+ {
+ surface = surface_under_pointer;
+ *x = x_tmp;
+ *y = y_tmp;
+ }
+
+ return GDK_MACOS_SURFACE (surface);
+ }
+ else
+ {
+ /* Finally check the grab window. */
+ GdkSurface *grab_surface = grab->surface;
+ get_surface_point_from_screen_point (grab_surface, point, x, y);
+ return GDK_MACOS_SURFACE (grab_surface);
+ }
+
+ return NULL;
+ }
+ else
+ {
+ /* The non-grabbed case. */
+ GdkSurface *surface_under_pointer;
+ int x_tmp, y_tmp;
+
+ /* Ignore all events but mouse moved that might be on the title
+ * bar (above the content view). The reason is that otherwise
+ * gdk gets confused about getting e.g. button presses with no
+ * window (the title bar is not known to it).
+ */
+ if (event_type != NSEventTypeMouseMoved)
+ {
+ if (*y < 0)
+ return NULL;
+ }
+
+ /* As for owner events, we need to use the surface under the
+ * pointer, not the window from the NSEvent.
+ */
+ surface_under_pointer = find_surface_under_pointer (self, point, &x_tmp, &y_tmp);
+ if (surface_under_pointer != NULL)
+ {
+ surface = surface_under_pointer;
+ *x = x_tmp;
+ *y = y_tmp;
+ }
+
+ return GDK_MACOS_SURFACE (surface);
+ }
+
+ return NULL;
+}
+
+/* This function finds the correct window to send an event to, taking
+ * into account grabs, event propagation, and event masks.
+ */
+static GdkMacosSurface *
+find_surface_for_ns_event (GdkMacosDisplay *self,
+ NSEvent *nsevent,
+ int *x,
+ int *y)
+{
+ GdkMacosBaseView *view;
+ GdkSurface *surface;
+ NSPoint point;
+ int x_tmp;
+ int y_tmp;
+
+ g_assert (GDK_IS_MACOS_DISPLAY (self));
+ g_assert (nsevent != NULL);
+ g_assert (x != NULL);
+ g_assert (y != NULL);
+
+ view = (GdkMacosBaseView *)[[nsevent window] contentView];
+
+ if (!(surface = get_surface_from_ns_event (self, nsevent, &point, x, y)))
+ return NULL;
+
+ _gdk_macos_display_from_display_coords (self, point.x, point.y, &x_tmp, &y_tmp);
+
+ switch ((int)[nsevent type])
+ {
+ case NSEventTypeLeftMouseDown:
+ case NSEventTypeRightMouseDown:
+ case NSEventTypeOtherMouseDown:
+ case NSEventTypeLeftMouseUp:
+ case NSEventTypeRightMouseUp:
+ case NSEventTypeOtherMouseUp:
+ case NSEventTypeLeftMouseDragged:
+ case NSEventTypeRightMouseDragged:
+ case NSEventTypeOtherMouseDragged:
+ case NSEventTypeMouseMoved:
+ case NSEventTypeScrollWheel:
+ case NSEventTypeMagnify:
+ case NSEventTypeRotate:
+ return find_surface_for_mouse_event (self, nsevent, x, y);
+
+ case NSEventTypeMouseEntered:
+ case NSEventTypeMouseExited:
+ /* Only handle our own entered/exited events, not the ones for the
+ * titlebar buttons.
+ */
+ if ([nsevent trackingArea] == [view trackingArea])
+ return GDK_MACOS_SURFACE (surface);
+ else
+ return NULL;
+
+ case NSEventTypeKeyDown:
+ case NSEventTypeKeyUp:
+ case NSEventTypeFlagsChanged:
+ return find_surface_for_keyboard_event (nsevent);
+
+ default:
+ /* Ignore everything else. */
+ return NULL;
+ }
+}
+
+GdkEvent *
+_gdk_macos_display_translate (GdkMacosDisplay *self,
+ NSEvent *nsevent)
+{
+ GdkMacosSurface *surface;
+ GdkMacosWindow *window;
+ NSEventType event_type;
+ GdkEvent *ret = NULL;
+ int x;
+ int y;
+
+ g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (self), NULL);
+ g_return_val_if_fail (nsevent != NULL, NULL);
+
+ /* There is no support for real desktop wide grabs, so we break
+ * grabs when the application loses focus (gets deactivated).
+ */
+ event_type = [nsevent type];
+ if (event_type == NSEventTypeAppKitDefined)
+ {
+ if ([nsevent subtype] == NSEventSubtypeApplicationDeactivated)
+ _gdk_macos_display_break_all_grabs (self, get_time_from_ns_event (nsevent));
+
+ /* This could potentially be used to break grabs when clicking
+ * on the title. The subtype 20 is undocumented so it's probably
+ * not a good idea: else if (subtype == 20) break_all_grabs ();
+ */
+
+ /* Leave all AppKit events to AppKit. */
+ return NULL;
+ }
+
+ if (!(surface = find_surface_for_ns_event (self, nsevent, &x, &y)))
+ return NULL;
+
+ if (!(window = (GdkMacosWindow *)_gdk_macos_surface_get_native (surface)))
+ return NULL;
+
+ /* Ignore events and break grabs while the window is being
+ * dragged. This is a workaround for the window getting events for
+ * the window title.
+ */
+ if ([window isInMove])
+ {
+ _gdk_macos_display_break_all_grabs (self, get_time_from_ns_event (nsevent));
+ return NULL;
+ }
+
+ /* Also when in a manual resize or move , we ignore events so that
+ * these are pushed to GdkMacosNSWindow's sendEvent handler.
+ */
+ if ([window isInManualResizeOrMove])
+ return NULL;
+
+ /* Make sure we have a GdkSurface */
+ if (!(surface = [window gdkSurface]))
+ return NULL;
+
+ /* Quartz handles resizing on its own, so stay out of the way. */
+ if (test_resize (nsevent, surface, x, y))
+ return NULL;
+
+ if ((event_type == NSEventTypeRightMouseDown ||
+ event_type == NSEventTypeOtherMouseDown ||
+ event_type == NSEventTypeLeftMouseDown))
+ {
+ if (![NSApp isActive])
+ [NSApp activateIgnoringOtherApps:YES];
+
+ if (![window isKeyWindow])
+ [window makeKeyWindow];
+ }
+
+ switch ((int)event_type)
+ {
+ case NSEventTypeLeftMouseDown:
+ case NSEventTypeRightMouseDown:
+ case NSEventTypeOtherMouseDown:
+ case NSEventTypeLeftMouseUp:
+ case NSEventTypeRightMouseUp:
+ case NSEventTypeOtherMouseUp:
+ ret = fill_button_event (self, surface, nsevent, x, y);
+ break;
+
+ case NSEventTypeLeftMouseDragged:
+ case NSEventTypeRightMouseDragged:
+ case NSEventTypeOtherMouseDragged:
+ case NSEventTypeMouseMoved:
+ ret = fill_motion_event (self, surface, nsevent, x, y);
+ break;
+
+ case NSEventTypeMagnify:
+ case NSEventTypeRotate:
+ ret = fill_pinch_event (self, surface, nsevent, x, y);
+ break;
+
+ case NSEventTypeMouseExited:
+ [[NSCursor arrowCursor] set];
+ /* fallthrough */
+ case NSEventTypeMouseEntered:
+ ret = synthesize_crossing_event (self, surface, nsevent, x, y);
+ break;
+
+ case NSEventTypeKeyDown:
+ case NSEventTypeKeyUp:
+ case NSEventTypeFlagsChanged: {
+ GdkEventType type = _gdk_macos_keymap_get_event_type (nsevent);
+
+ if (type)
+ ret = fill_key_event (self, surface, nsevent, type);
+
+ break;
+ }
+
+ case NSEventTypeScrollWheel:
+ ret = fill_scroll_event (self, surface, nsevent, x, y);
+ break;
+
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+void
+_gdk_macos_display_synthesize_motion (GdkMacosDisplay *self,
+ GdkMacosSurface *surface)
+{
+ GdkModifierType state;
+ GdkEvent *event;
+ GdkSeat *seat;
+ NSPoint point;
+ GList *node;
+ int x;
+ int y;
+
+ g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
+ g_return_if_fail (GDK_IS_MACOS_SURFACE (surface));
+
+ seat = gdk_display_get_default_seat (GDK_DISPLAY (self));
+ point = [NSEvent mouseLocation];
+ _gdk_macos_display_from_display_coords (self, point.x, point.y, &x, &y);
+
+ state = _gdk_macos_display_get_current_keyboard_modifiers (self) |
+ _gdk_macos_display_get_current_mouse_modifiers (self);
+
+ event = gdk_motion_event_new (GDK_SURFACE (surface),
+ gdk_seat_get_pointer (seat),
+ NULL,
+ NULL,
+ get_time_from_ns_event ([NSApp currentEvent]),
+ state,
+ x,
+ y,
+ NULL);
+ node = _gdk_event_queue_append (GDK_DISPLAY (self), event);
+ _gdk_windowing_got_event (GDK_DISPLAY (self), node, event, 0);
+}
+
+void
+_gdk_macos_display_send_button_event (GdkMacosDisplay *self,
+ NSEvent *nsevent)
+{
+ GdkMacosSurface *surface;
+ GdkEvent *event;
+ int x;
+ int y;
+
+ g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
+ g_return_if_fail (nsevent != NULL);
+
+ if ((surface = find_surface_for_ns_event (self, nsevent, &x, &y)) &&
+ (event = fill_button_event (self, surface, nsevent, x, y)))
+ _gdk_windowing_got_event (GDK_DISPLAY (self),
+ _gdk_event_queue_append (GDK_DISPLAY (self), event),
+ event,
+ _gdk_display_get_next_serial (GDK_DISPLAY (self)));
+}
--- /dev/null
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#include <AppKit/AppKit.h>
+
+#import "GdkMacosWindow.h"
+
+#include "gdkdisplayprivate.h"
+#include "gdkeventsprivate.h"
+
+#include "gdkdisplaylinksource.h"
+#include "gdkmacosclipboard-private.h"
+#include "gdkmacoscairocontext-private.h"
+#include "gdkmacoseventsource-private.h"
+#include "gdkmacosdisplay-private.h"
+#include "gdkmacosglcontext-private.h"
+#include "gdkmacoskeymap-private.h"
+#include "gdkmacosmonitor-private.h"
+#include "gdkmacosseat-private.h"
+#include "gdkmacossurface-private.h"
+#include "gdkmacosutils-private.h"
+
+/**
+ * SECTION:macos_interaction
+ * @Short_description: macOS backend-specific functions
+ * @Title: macOS Interaction
+ * @Include: gdk/macos/gdkmacos.h
+ *
+ * The functions in this section are specific to the GDK macOS backend.
+ * To use them, you need to include the `<gdk/macos/gdkmacos.h>` header and
+ * use the macOS-specific pkg-config `gtk4-macos` file to build your
+ * application.
+ *
+ * To make your code compile with other GDK backends, guard backend-specific
+ * calls by an ifdef as follows. Since GDK may be built with multiple
+ * backends, you should also check for the backend that is in use (e.g. by
+ * using the GDK_IS_MACOS_DISPLAY() macro).
+ * |[<!-- language="C" -->
+ * #ifdef GDK_WINDOWING_MACOS
+ * if (GDK_IS_MACOS_DISPLAY (display))
+ * {
+ * // make macOS-specific calls here
+ * }
+ * else
+ * #endif
+ * #ifdef GDK_WINDOWING_X11
+ * if (GDK_IS_X11_DISPLAY (display))
+ * {
+ * // make X11-specific calls here
+ * }
+ * else
+ * #endif
+ * g_error ("Unsupported GDK backend");
+ * ]|
+ */
+
+G_DEFINE_TYPE (GdkMacosDisplay, gdk_macos_display, GDK_TYPE_DISPLAY)
+
+static GSource *event_source;
+
+static GdkMacosMonitor *
+get_monitor (GdkMacosDisplay *self,
+ guint position)
+{
+ GdkMacosMonitor *monitor;
+
+ g_assert (GDK_IS_MACOS_DISPLAY (self));
+
+ /* Get the monitor but return a borrowed reference */
+ monitor = g_list_model_get_item (G_LIST_MODEL (self->monitors), position);
+ if (monitor != NULL)
+ g_object_unref (monitor);
+
+ return monitor;
+}
+
+static gboolean
+gdk_macos_display_get_setting (GdkDisplay *display,
+ const gchar *setting,
+ GValue *value)
+{
+ return _gdk_macos_display_get_setting (GDK_MACOS_DISPLAY (display), setting, value);
+}
+
+static GListModel *
+gdk_macos_display_get_monitors (GdkDisplay *display)
+{
+ return G_LIST_MODEL (GDK_MACOS_DISPLAY (display)->monitors);
+}
+
+static GdkMonitor *
+gdk_macos_display_get_monitor_at_surface (GdkDisplay *display,
+ GdkSurface *surface)
+{
+ GdkMacosDisplay *self = (GdkMacosDisplay *)display;
+ CGDirectDisplayID screen_id;
+ guint n_monitors;
+
+ g_assert (GDK_IS_MACOS_DISPLAY (self));
+ g_assert (GDK_IS_MACOS_SURFACE (surface));
+
+ screen_id = _gdk_macos_surface_get_screen_id (GDK_MACOS_SURFACE (surface));
+ n_monitors = g_list_model_get_n_items (G_LIST_MODEL (self->monitors));
+
+ for (guint i = 0; i < n_monitors; i++)
+ {
+ GdkMacosMonitor *monitor = get_monitor (self, i);
+
+ if (screen_id == _gdk_macos_monitor_get_screen_id (monitor))
+ return GDK_MONITOR (monitor);
+ }
+
+ return GDK_MONITOR (get_monitor (self, 0));
+}
+
+static GdkMacosMonitor *
+gdk_macos_display_find_monitor (GdkMacosDisplay *self,
+ CGDirectDisplayID screen_id)
+{
+ guint n_monitors;
+
+ g_assert (GDK_IS_MACOS_DISPLAY (self));
+
+ n_monitors = g_list_model_get_n_items (G_LIST_MODEL (self->monitors));
+
+ for (guint i = 0; i < n_monitors; i++)
+ {
+ GdkMacosMonitor *monitor = get_monitor (self, i);
+
+ if (screen_id == _gdk_macos_monitor_get_screen_id (monitor))
+ return monitor;
+ }
+
+ return NULL;
+}
+
+static void
+gdk_macos_display_update_bounds (GdkMacosDisplay *self)
+{
+ GDK_BEGIN_MACOS_ALLOC_POOL;
+
+ g_assert (GDK_IS_MACOS_DISPLAY (self));
+
+ self->min_x = G_MAXINT;
+ self->min_y = G_MAXINT;
+
+ self->max_x = G_MININT;
+ self->max_y = G_MININT;
+
+ for (id obj in [NSScreen screens])
+ {
+ NSRect geom = [(NSScreen *)obj frame];
+
+ self->min_x = MIN (self->min_x, geom.origin.x);
+ self->min_y = MIN (self->min_y, geom.origin.y);
+ self->max_x = MAX (self->max_x, geom.origin.x + geom.size.width);
+ self->max_y = MAX (self->max_y, geom.origin.y + geom.size.height);
+ }
+
+ self->width = self->max_x - self->min_x;
+ self->height = self->max_y - self->min_y;
+
+ GDK_END_MACOS_ALLOC_POOL;
+}
+
+static void
+gdk_macos_display_monitors_changed_cb (CFNotificationCenterRef center,
+ void *observer,
+ CFStringRef name,
+ const void *object,
+ CFDictionaryRef userInfo)
+{
+ GdkMacosDisplay *self = observer;
+
+ g_assert (GDK_IS_MACOS_DISPLAY (self));
+
+ _gdk_macos_display_reload_monitors (self);
+
+ /* Now we need to update all our surface positions since they
+ * probably just changed origins. We ignore the popup surfaces
+ * since we can rely on the toplevel surfaces to handle that.
+ */
+ for (const GList *iter = _gdk_macos_display_get_surfaces (self);
+ iter != NULL;
+ iter = iter->next)
+ {
+ GdkMacosSurface *surface = iter->data;
+
+ g_assert (GDK_IS_MACOS_SURFACE (surface));
+
+ if (GDK_IS_TOPLEVEL (surface))
+ _gdk_macos_surface_update_position (surface);
+ }
+}
+
+static void
+gdk_macos_display_user_defaults_changed_cb (CFNotificationCenterRef center,
+ void *observer,
+ CFStringRef name,
+ const void *object,
+ CFDictionaryRef userInfo)
+{
+ GdkMacosDisplay *self = observer;
+
+ g_assert (GDK_IS_MACOS_DISPLAY (self));
+
+ _gdk_macos_display_reload_settings (self);
+}
+
+void
+_gdk_macos_display_reload_monitors (GdkMacosDisplay *self)
+{
+ GDK_BEGIN_MACOS_ALLOC_POOL;
+
+ GArray *seen;
+ guint n_monitors;
+
+ g_assert (GDK_IS_MACOS_DISPLAY (self));
+
+ gdk_macos_display_update_bounds (self);
+
+ seen = g_array_new (FALSE, FALSE, sizeof (CGDirectDisplayID));
+
+ for (id obj in [NSScreen screens])
+ {
+ CGDirectDisplayID screen_id;
+ GdkMacosMonitor *monitor;
+
+ screen_id = [[[obj deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue];
+ g_array_append_val (seen, screen_id);
+
+ if ((monitor = gdk_macos_display_find_monitor (self, screen_id)))
+ {
+ _gdk_macos_monitor_reconfigure (monitor);
+ }
+ else
+ {
+ monitor = _gdk_macos_monitor_new (self, screen_id);
+ g_list_store_append (self->monitors, monitor);
+ g_object_unref (monitor);
+ }
+ }
+
+ n_monitors = g_list_model_get_n_items (G_LIST_MODEL (self->monitors));
+
+ for (guint i = n_monitors; i > 0; i--)
+ {
+ GdkMacosMonitor *monitor = get_monitor (self, i - 1);
+ CGDirectDisplayID screen_id = _gdk_macos_monitor_get_screen_id (monitor);
+ gboolean found = FALSE;
+
+ for (guint j = 0; j < seen->len; j++)
+ {
+ if (screen_id == g_array_index (seen, CGDirectDisplayID, j))
+ {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found)
+ g_list_store_remove (self->monitors, i - 1);
+ }
+
+ g_array_unref (seen);
+
+ GDK_END_MACOS_ALLOC_POOL;
+}
+
+static void
+gdk_macos_display_load_seat (GdkMacosDisplay *self)
+{
+ GdkSeat *seat;
+
+ g_assert (GDK_IS_MACOS_DISPLAY (self));
+
+ seat = _gdk_macos_seat_new (self);
+ gdk_display_add_seat (GDK_DISPLAY (self), seat);
+ g_object_unref (seat);
+}
+
+static gboolean
+gdk_macos_display_frame_cb (gpointer data)
+{
+ GdkMacosDisplay *self = data;
+ GdkDisplayLinkSource *source;
+ gint64 presentation_time;
+ gint64 now;
+ GList *iter;
+
+ g_assert (GDK_IS_MACOS_DISPLAY (self));
+
+ source = (GdkDisplayLinkSource *)self->frame_source;
+
+ presentation_time = source->presentation_time;
+ now = g_source_get_time ((GSource *)source);
+
+ iter = self->awaiting_frames.head;
+
+ while (iter != NULL)
+ {
+ GdkMacosSurface *surface = iter->data;
+
+ g_assert (GDK_IS_MACOS_SURFACE (surface));
+
+ iter = iter->next;
+
+ _gdk_macos_display_remove_frame_callback (self, surface);
+ _gdk_macos_surface_thaw (surface,
+ source->presentation_time,
+ source->refresh_interval);
+ }
+
+ return G_SOURCE_CONTINUE;
+}
+
+static void
+gdk_macos_display_load_display_link (GdkMacosDisplay *self)
+{
+ self->frame_source = gdk_display_link_source_new ();
+ g_source_set_callback (self->frame_source,
+ gdk_macos_display_frame_cb,
+ self,
+ NULL);
+ g_source_attach (self->frame_source, NULL);
+}
+
+static const gchar *
+gdk_macos_display_get_name (GdkDisplay *display)
+{
+ return GDK_MACOS_DISPLAY (display)->name;
+}
+
+static void
+gdk_macos_display_beep (GdkDisplay *display)
+{
+ NSBeep ();
+}
+
+static void
+gdk_macos_display_flush (GdkDisplay *display)
+{
+ /* Not Supported */
+}
+
+static void
+gdk_macos_display_sync (GdkDisplay *display)
+{
+ /* Not Supported */
+}
+
+static gulong
+gdk_macos_display_get_next_serial (GdkDisplay *display)
+{
+ return 0;
+}
+
+static gboolean
+gdk_macos_display_has_pending (GdkDisplay *display)
+{
+ return _gdk_event_queue_find_first (display) ||
+ _gdk_macos_event_source_check_pending ();
+}
+
+static void
+gdk_macos_display_notify_startup_complete (GdkDisplay *display,
+ const gchar *startup_notification_id)
+{
+ /* Not Supported */
+}
+
+static void
+gdk_macos_display_queue_events (GdkDisplay *display)
+{
+ GdkMacosDisplay *self = (GdkMacosDisplay *)display;
+ NSEvent *nsevent;
+
+ g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
+
+ if ((nsevent = _gdk_macos_event_source_get_pending ()))
+ {
+ GdkEvent *event = _gdk_macos_display_translate (self, nsevent);
+
+ if (event != NULL)
+ _gdk_windowing_got_event (GDK_DISPLAY (self),
+ _gdk_event_queue_append (GDK_DISPLAY (self), event),
+ event,
+ 0);
+ else
+ [NSApp sendEvent:nsevent];
+
+ [nsevent release];
+ }
+}
+
+static void
+_gdk_macos_display_surface_added (GdkMacosDisplay *self,
+ GdkMacosSurface *surface)
+{
+ g_assert (GDK_IS_MACOS_DISPLAY (self));
+ g_assert (GDK_IS_MACOS_SURFACE (surface));
+ g_assert (!queue_contains (&self->sorted_surfaces, &surface->sorted));
+ g_assert (!queue_contains (&self->main_surfaces, &surface->main));
+ g_assert (!queue_contains (&self->awaiting_frames, &surface->frame));
+ g_assert (surface->sorted.data == surface);
+ g_assert (surface->main.data == surface);
+ g_assert (surface->frame.data == surface);
+
+ if (GDK_IS_TOPLEVEL (surface))
+ g_queue_push_tail_link (&self->main_surfaces, &surface->main);
+
+ _gdk_macos_display_clear_sorting (self);
+}
+
+void
+_gdk_macos_display_surface_removed (GdkMacosDisplay *self,
+ GdkMacosSurface *surface)
+{
+ g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
+ g_return_if_fail (GDK_IS_MACOS_SURFACE (surface));
+
+ if (self->keyboard_surface == surface)
+ _gdk_macos_display_surface_resigned_key (self, surface);
+
+ g_queue_unlink (&self->sorted_surfaces, &surface->sorted);
+
+ if (queue_contains (&self->main_surfaces, &surface->main))
+ _gdk_macos_display_surface_resigned_main (self, surface);
+
+ if (queue_contains (&self->awaiting_frames, &surface->frame))
+ g_queue_unlink (&self->awaiting_frames, &surface->frame);
+
+ g_return_if_fail (self->keyboard_surface != surface);
+}
+
+void
+_gdk_macos_display_surface_became_key (GdkMacosDisplay *self,
+ GdkMacosSurface *surface)
+{
+ GdkDevice *keyboard;
+ GdkEvent *event;
+ GdkSeat *seat;
+
+ g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
+ g_return_if_fail (GDK_IS_MACOS_SURFACE (surface));
+ g_return_if_fail (self->keyboard_surface == NULL);
+
+ self->keyboard_surface = surface;
+
+ seat = gdk_display_get_default_seat (GDK_DISPLAY (self));
+ keyboard = gdk_seat_get_keyboard (seat);
+ event = gdk_focus_event_new (GDK_SURFACE (surface), keyboard, NULL, TRUE);
+ _gdk_event_queue_append (GDK_DISPLAY (self), event);
+
+ /* We just became the active window. Unlike X11, Mac OS X does
+ * not send us motion events while the window does not have focus
+ * ("is not key"). We send a dummy motion notify event now, so that
+ * everything in the window is set to correct state.
+ */
+ _gdk_macos_display_synthesize_motion (self, surface);
+}
+
+void
+_gdk_macos_display_surface_resigned_key (GdkMacosDisplay *self,
+ GdkMacosSurface *surface)
+{
+ g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
+ g_return_if_fail (GDK_IS_MACOS_SURFACE (surface));
+
+ if (self->keyboard_surface == surface)
+ {
+ GdkDevice *keyboard;
+ GdkEvent *event;
+ GdkSeat *seat;
+
+ seat = gdk_display_get_default_seat (GDK_DISPLAY (self));
+ keyboard = gdk_seat_get_keyboard (seat);
+ event = gdk_focus_event_new (GDK_SURFACE (surface), keyboard, NULL, FALSE);
+ _gdk_event_queue_append (GDK_DISPLAY (self), event);
+ }
+
+ self->keyboard_surface = NULL;
+
+ _gdk_macos_display_clear_sorting (self);
+}
+
+void
+_gdk_macos_display_surface_became_main (GdkMacosDisplay *self,
+ GdkMacosSurface *surface)
+{
+ g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
+ g_return_if_fail (GDK_IS_MACOS_SURFACE (surface));
+
+ if (queue_contains (&self->main_surfaces, &surface->main))
+ g_queue_unlink (&self->main_surfaces, &surface->main);
+
+ g_queue_push_head_link (&self->main_surfaces, &surface->main);
+
+ _gdk_macos_display_clear_sorting (self);
+}
+
+void
+_gdk_macos_display_surface_resigned_main (GdkMacosDisplay *self,
+ GdkMacosSurface *surface)
+{
+ GdkMacosSurface *new_surface = NULL;
+
+ g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
+ g_return_if_fail (GDK_IS_MACOS_SURFACE (surface));
+
+ if (queue_contains (&self->main_surfaces, &surface->main))
+ g_queue_unlink (&self->main_surfaces, &surface->main);
+
+ _gdk_macos_display_clear_sorting (self);
+
+ if (GDK_SURFACE (surface)->transient_for &&
+ gdk_surface_get_mapped (GDK_SURFACE (surface)->transient_for))
+ {
+ new_surface = GDK_MACOS_SURFACE (GDK_SURFACE (surface)->transient_for);
+ }
+ else
+ {
+ const GList *surfaces = _gdk_macos_display_get_surfaces (self);
+
+ for (const GList *iter = surfaces; iter; iter = iter->next)
+ {
+ GdkMacosSurface *item = iter->data;
+
+ g_assert (GDK_IS_MACOS_SURFACE (item));
+
+ if (item == surface)
+ continue;
+
+ if (GDK_SURFACE_IS_MAPPED (GDK_SURFACE (item)))
+ {
+ new_surface = item;
+ break;
+ }
+ }
+ }
+
+ if (new_surface != NULL)
+ {
+ NSWindow *nswindow = _gdk_macos_surface_get_native (new_surface);
+ [nswindow makeKeyAndOrderFront:nswindow];
+ }
+
+ _gdk_macos_display_clear_sorting (self);
+}
+
+static GdkSurface *
+gdk_macos_display_create_surface (GdkDisplay *display,
+ GdkSurfaceType surface_type,
+ GdkSurface *parent,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ GdkMacosDisplay *self = (GdkMacosDisplay *)display;
+ GdkMacosSurface *surface;
+
+ g_assert (GDK_IS_MACOS_DISPLAY (self));
+ g_assert (!parent || GDK_IS_MACOS_SURFACE (parent));
+
+ surface = _gdk_macos_surface_new (self, surface_type, parent, x, y, width, height);
+
+ if (surface != NULL)
+ _gdk_macos_display_surface_added (self, surface);
+
+ return GDK_SURFACE (surface);
+}
+
+static GdkKeymap *
+gdk_macos_display_get_keymap (GdkDisplay *display)
+{
+ GdkMacosDisplay *self = (GdkMacosDisplay *)display;
+
+ g_assert (GDK_IS_MACOS_DISPLAY (self));
+
+ return GDK_KEYMAP (self->keymap);
+}
+
+static void
+gdk_macos_display_load_clipboard (GdkMacosDisplay *self)
+{
+ g_assert (GDK_IS_MACOS_DISPLAY (self));
+
+ GDK_DISPLAY (self)->clipboard = _gdk_macos_clipboard_new (self);
+}
+
+static gboolean
+gdk_macos_display_make_gl_context_current (GdkDisplay *display,
+ GdkGLContext *gl_context)
+{
+ g_assert (GDK_IS_MACOS_DISPLAY (display));
+ g_assert (GDK_IS_MACOS_GL_CONTEXT (gl_context));
+
+ return _gdk_macos_gl_context_make_current (GDK_MACOS_GL_CONTEXT (gl_context));
+}
+
+static void
+gdk_macos_display_finalize (GObject *object)
+{
+ GdkMacosDisplay *self = (GdkMacosDisplay *)object;
+
+ CFNotificationCenterRemoveObserver (CFNotificationCenterGetDistributedCenter (),
+ self,
+ CFSTR ("NSApplicationDidChangeScreenParametersNotification"),
+ NULL);
+
+ CFNotificationCenterRemoveObserver (CFNotificationCenterGetDistributedCenter (),
+ self,
+ CFSTR ("NSUserDefaultsDidChangeNotification"),
+ NULL);
+
+ g_clear_object (&GDK_DISPLAY (self)->clipboard);
+ g_clear_pointer (&self->frame_source, g_source_unref);
+ g_clear_object (&self->monitors);
+ g_clear_pointer (&self->name, g_free);
+
+ G_OBJECT_CLASS (gdk_macos_display_parent_class)->finalize (object);
+}
+
+static void
+gdk_macos_display_class_init (GdkMacosDisplayClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GdkDisplayClass *display_class = GDK_DISPLAY_CLASS (klass);
+
+ object_class->finalize = gdk_macos_display_finalize;
+
+ display_class->cairo_context_type = GDK_TYPE_MACOS_CAIRO_CONTEXT;
+
+ display_class->beep = gdk_macos_display_beep;
+ display_class->create_surface = gdk_macos_display_create_surface;
+ display_class->flush = gdk_macos_display_flush;
+ display_class->get_keymap = gdk_macos_display_get_keymap;
+ display_class->get_monitors = gdk_macos_display_get_monitors;
+ display_class->get_monitor_at_surface = gdk_macos_display_get_monitor_at_surface;
+ display_class->get_next_serial = gdk_macos_display_get_next_serial;
+ display_class->get_name = gdk_macos_display_get_name;
+ display_class->get_setting = gdk_macos_display_get_setting;
+ display_class->has_pending = gdk_macos_display_has_pending;
+ display_class->make_gl_context_current = gdk_macos_display_make_gl_context_current;
+ display_class->notify_startup_complete = gdk_macos_display_notify_startup_complete;
+ display_class->queue_events = gdk_macos_display_queue_events;
+ display_class->sync = gdk_macos_display_sync;
+}
+
+static void
+gdk_macos_display_init (GdkMacosDisplay *self)
+{
+ self->monitors = g_list_store_new (GDK_TYPE_MONITOR);
+
+ gdk_display_set_composited (GDK_DISPLAY (self), TRUE);
+ gdk_display_set_input_shapes (GDK_DISPLAY (self), FALSE);
+ gdk_display_set_rgba (GDK_DISPLAY (self), TRUE);
+}
+
+GdkDisplay *
+_gdk_macos_display_open (const gchar *display_name)
+{
+ static GdkMacosDisplay *self;
+ ProcessSerialNumber psn = { 0, kCurrentProcess };
+
+ /* Until we can have multiple GdkMacosEventSource instances
+ * running concurrently, we can't exactly support multiple
+ * display connections. So just short-circuit if we already
+ * have one active.
+ */
+ if (self != NULL)
+ return NULL;
+
+ GDK_NOTE (MISC, g_message ("opening display %s", display_name ? display_name : ""));
+
+ /* Make the current process a foreground application, i.e. an app
+ * with a user interface, in case we're not running from a .app bundle
+ */
+ TransformProcessType (&psn, kProcessTransformToForegroundApplication);
+
+ [NSApplication sharedApplication];
+
+ self = g_object_new (GDK_TYPE_MACOS_DISPLAY, NULL);
+ self->name = g_strdup (display_name);
+ self->keymap = _gdk_macos_keymap_new (self);
+
+ gdk_macos_display_load_seat (self);
+ gdk_macos_display_load_clipboard (self);
+
+ /* Load CVDisplayLink before monitors to access refresh rates */
+ gdk_macos_display_load_display_link (self);
+ _gdk_macos_display_reload_monitors (self);
+
+ CFNotificationCenterAddObserver (CFNotificationCenterGetLocalCenter (),
+ self,
+ gdk_macos_display_monitors_changed_cb,
+ CFSTR ("NSApplicationDidChangeScreenParametersNotification"),
+ NULL,
+ CFNotificationSuspensionBehaviorDeliverImmediately);
+
+ CFNotificationCenterAddObserver (CFNotificationCenterGetDistributedCenter (),
+ self,
+ gdk_macos_display_user_defaults_changed_cb,
+ CFSTR ("NSUserDefaultsDidChangeNotification"),
+ NULL,
+ CFNotificationSuspensionBehaviorDeliverImmediately);
+
+ if (event_source == NULL)
+ {
+ event_source = _gdk_macos_event_source_new (self);
+ g_source_attach (event_source, NULL);
+ }
+
+ g_object_add_weak_pointer (G_OBJECT (self), (gpointer *)&self);
+
+ gdk_display_emit_opened (GDK_DISPLAY (self));
+
+ return GDK_DISPLAY (self);
+}
+
+void
+_gdk_macos_display_to_display_coords (GdkMacosDisplay *self,
+ int x,
+ int y,
+ int *out_x,
+ int *out_y)
+{
+ g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
+
+ if (out_y)
+ *out_y = self->height - y + self->min_y;
+
+ if (out_x)
+ *out_x = x + self->min_x;
+}
+
+void
+_gdk_macos_display_from_display_coords (GdkMacosDisplay *self,
+ int x,
+ int y,
+ int *out_x,
+ int *out_y)
+{
+ g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
+
+ if (out_y != NULL)
+ *out_y = self->height - y + self->min_y;
+
+ if (out_x != NULL)
+ *out_x = x - self->min_x;
+}
+
+GdkMonitor *
+_gdk_macos_display_get_monitor_at_coords (GdkMacosDisplay *self,
+ int x,
+ int y)
+{
+ guint n_monitors;
+
+ g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (self), NULL);
+
+ n_monitors = g_list_model_get_n_items (G_LIST_MODEL (self->monitors));
+
+ for (guint i = 0; i < n_monitors; i++)
+ {
+ GdkMacosMonitor *monitor = get_monitor (self, i);
+
+ if (gdk_rectangle_contains_point (&GDK_MONITOR (monitor)->geometry, x, y))
+ return GDK_MONITOR (monitor);
+ }
+
+ return NULL;
+}
+
+GdkMonitor *
+_gdk_macos_display_get_monitor_at_display_coords (GdkMacosDisplay *self,
+ int x,
+ int y)
+{
+ g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (self), NULL);
+
+ _gdk_macos_display_from_display_coords (self, x, y, &x, &y);
+
+ return _gdk_macos_display_get_monitor_at_coords (self, x, y);
+}
+
+NSScreen *
+_gdk_macos_display_get_screen_at_display_coords (GdkMacosDisplay *self,
+ int x,
+ int y)
+{
+ GDK_BEGIN_MACOS_ALLOC_POOL;
+
+ NSArray *screens;
+ NSScreen *screen = NULL;
+
+ g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (self), NULL);
+
+ screens = [NSScreen screens];
+
+ for (id obj in screens)
+ {
+ NSRect geom = [obj frame];
+
+ if (x >= geom.origin.x && x <= geom.origin.x + geom.size.width &&
+ y >= geom.origin.y && y <= geom.origin.y + geom.size.height)
+ {
+ screen = obj;
+ break;
+ }
+ }
+
+ GDK_END_MACOS_ALLOC_POOL;
+
+ return screen;
+}
+
+void
+_gdk_macos_display_break_all_grabs (GdkMacosDisplay *self,
+ guint32 time)
+{
+ GdkDevice *devices[2];
+ GdkSeat *seat;
+
+ g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
+
+ seat = gdk_display_get_default_seat (GDK_DISPLAY (self));
+ devices[0] = gdk_seat_get_keyboard (seat);
+ devices[1] = gdk_seat_get_pointer (seat);
+
+ for (guint i = 0; i < G_N_ELEMENTS (devices); i++)
+ {
+ GdkDevice *device = devices[i];
+ GdkDeviceGrabInfo *grab;
+
+ grab = _gdk_display_get_last_device_grab (GDK_DISPLAY (self), device);
+
+ if (grab != NULL)
+ {
+ GdkEvent *event;
+ GList *node;
+
+ event = gdk_grab_broken_event_new (grab->surface,
+ device,
+ NULL,
+ grab->surface,
+ TRUE);
+ node = _gdk_event_queue_append (GDK_DISPLAY (self), event);
+ _gdk_windowing_got_event (GDK_DISPLAY (self), node, event, 0);
+ }
+ }
+}
+
+void
+_gdk_macos_display_queue_events (GdkMacosDisplay *self)
+{
+ g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
+
+ gdk_macos_display_queue_events (GDK_DISPLAY (self));
+}
+
+static GdkMacosSurface *
+_gdk_macos_display_get_surface_at_coords (GdkMacosDisplay *self,
+ int x,
+ int y,
+ int *surface_x,
+ int *surface_y)
+{
+ const GList *surfaces;
+
+ g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (self), NULL);
+ g_return_val_if_fail (surface_x != NULL, NULL);
+ g_return_val_if_fail (surface_y != NULL, NULL);
+
+ surfaces = _gdk_macos_display_get_surfaces (self);
+
+ for (const GList *iter = surfaces; iter; iter = iter->next)
+ {
+ GdkSurface *surface = iter->data;
+ NSWindow *nswindow;
+
+ g_assert (GDK_IS_MACOS_SURFACE (surface));
+
+ if (!gdk_surface_get_mapped (surface))
+ continue;
+
+ nswindow = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (surface));
+
+ if (x >= GDK_MACOS_SURFACE (surface)->root_x &&
+ y >= GDK_MACOS_SURFACE (surface)->root_y &&
+ x <= (GDK_MACOS_SURFACE (surface)->root_x + surface->width) &&
+ y <= (GDK_MACOS_SURFACE (surface)->root_y + surface->height))
+ {
+ *surface_x = x - GDK_MACOS_SURFACE (surface)->root_x;
+ *surface_y = y - GDK_MACOS_SURFACE (surface)->root_y;
+
+ return GDK_MACOS_SURFACE (surface);
+ }
+ }
+
+ *surface_x = 0;
+ *surface_y = 0;
+
+ return NULL;
+}
+
+GdkMacosSurface *
+_gdk_macos_display_get_surface_at_display_coords (GdkMacosDisplay *self,
+ double x,
+ double y,
+ int *surface_x,
+ int *surface_y)
+{
+ int x_gdk;
+ int y_gdk;
+
+ g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (self), NULL);
+ g_return_val_if_fail (surface_x != NULL, NULL);
+ g_return_val_if_fail (surface_y != NULL, NULL);
+
+ _gdk_macos_display_from_display_coords (self, x, y, &x_gdk, &y_gdk);
+
+ return _gdk_macos_display_get_surface_at_coords (self, x_gdk, y_gdk, surface_x, surface_y);
+}
+
+void
+_gdk_macos_display_add_frame_callback (GdkMacosDisplay *self,
+ GdkMacosSurface *surface)
+{
+ g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
+ g_return_if_fail (GDK_IS_MACOS_SURFACE (surface));
+
+ if (!queue_contains (&self->awaiting_frames, &surface->frame))
+ {
+ g_queue_push_tail_link (&self->awaiting_frames, &surface->frame);
+
+ if (self->awaiting_frames.length == 1)
+ gdk_display_link_source_unpause ((GdkDisplayLinkSource *)self->frame_source);
+ }
+}
+
+void
+_gdk_macos_display_remove_frame_callback (GdkMacosDisplay *self,
+ GdkMacosSurface *surface)
+{
+ g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
+ g_return_if_fail (GDK_IS_MACOS_SURFACE (surface));
+
+ if (queue_contains (&self->awaiting_frames, &surface->frame))
+ {
+ g_queue_unlink (&self->awaiting_frames, &surface->frame);
+
+ if (self->awaiting_frames.length == 0)
+ gdk_display_link_source_pause ((GdkDisplayLinkSource *)self->frame_source);
+ }
+}
+
+NSWindow *
+_gdk_macos_display_find_native_under_pointer (GdkMacosDisplay *self,
+ int *x,
+ int *y)
+{
+ GdkMacosSurface *surface;
+ NSPoint point;
+
+ g_assert (GDK_IS_MACOS_DISPLAY (self));
+
+ point = [NSEvent mouseLocation];
+
+ surface = _gdk_macos_display_get_surface_at_display_coords (self, point.x, point.y, x, y);
+ if (surface != NULL)
+ return _gdk_macos_surface_get_native (surface);
+
+ return NULL;
+}
+
+int
+_gdk_macos_display_get_nominal_refresh_rate (GdkMacosDisplay *self)
+{
+ g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (self), 60 * 1000);
+
+ if (self->frame_source == NULL)
+ return 60 * 1000;
+
+ return ((GdkDisplayLinkSource *)self->frame_source)->refresh_rate;
+}
+
+void
+_gdk_macos_display_clear_sorting (GdkMacosDisplay *self)
+{
+ g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
+
+ self->sorted_surfaces.head = NULL;
+ self->sorted_surfaces.tail = NULL;
+ self->sorted_surfaces.length = 0;
+}
+
+const GList *
+_gdk_macos_display_get_surfaces (GdkMacosDisplay *self)
+{
+ g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (self), NULL);
+
+ if (self->sorted_surfaces.length == 0)
+ {
+ GDK_BEGIN_MACOS_ALLOC_POOL;
+
+ NSArray *array = [NSApp orderedWindows];
+ GQueue sorted = G_QUEUE_INIT;
+
+ for (id obj in array)
+ {
+ NSWindow *nswindow = (NSWindow *)obj;
+ GdkMacosSurface *surface;
+
+ if (!GDK_IS_MACOS_WINDOW (nswindow))
+ continue;
+
+ surface = [(GdkMacosWindow *)nswindow gdkSurface];
+
+ surface->sorted.prev = NULL;
+ surface->sorted.next = NULL;
+
+ g_queue_push_tail_link (&sorted, &surface->sorted);
+ }
+
+ self->sorted_surfaces = sorted;
+
+ /* We don't get notification of clipboard changes from the system so we
+ * instead update it every time the foreground changes (and thusly
+ * rebuild the sorted list). Things could change other ways, such as
+ * with scripts, but that is currently out of scope for us.
+ */
+ _gdk_macos_clipboard_check_externally_modified (
+ GDK_MACOS_CLIPBOARD (GDK_DISPLAY (self)->clipboard));
+
+ GDK_END_MACOS_ALLOC_POOL;
+ }
+
+ return self->sorted_surfaces.head;
+}
+
+void
+_gdk_macos_display_warp_pointer (GdkMacosDisplay *self,
+ int x,
+ int y)
+{
+ g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
+
+ _gdk_macos_display_to_display_coords (self, x, y, &x, &y);
+
+ CGWarpMouseCursorPosition ((CGPoint) { x, y });
+}
--- /dev/null
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef __GDK_MACOS_DISPLAY_H__
+#define __GDK_MACOS_DISPLAY_H__
+
+#if !defined (__GDKMACOS_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gdk/macos/gdkmacos.h> can be included directly."
+#endif
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+#ifdef GTK_COMPILATION
+typedef struct _GdkMacosDisplay GdkMacosDisplay;
+#else
+typedef GdkDisplay GdkMacosDisplay;
+#endif
+typedef struct _GdkMacosDisplayClass GdkMacosDisplayClass;
+
+#define GDK_TYPE_MACOS_DISPLAY (gdk_macos_display_get_type())
+#define GDK_MACOS_DISPLAY(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_MACOS_DISPLAY, GdkMacosDisplay))
+#define GDK_IS_MACOS_DISPLAY(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MACOS_DISPLAY))
+
+GDK_AVAILABLE_IN_ALL
+GType gdk_macos_display_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GDK_MACOS_DISPLAY_H__ */
--- /dev/null
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef __GDK_MACOS_DRAG_PRIVATE_H__
+#define __GDK_MACOS_DRAG_PRIVATE_H__
+
+#include "gdkdragprivate.h"
+
+#include "gdkmacosdragsurface-private.h"
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_MACOS_DRAG (gdk_macos_drag_get_type ())
+#define GDK_MACOS_DRAG(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_MACOS_DRAG, GdkMacosDrag))
+#define GDK_MACOS_DRAG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_MACOS_DRAG, GdkMacosDragClass))
+#define GDK_IS_MACOS_DRAG(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MACOS_DRAG))
+#define GDK_IS_MACOS_DRAG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_MACOS_DRAG))
+#define GDK_MACOS_DRAG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_MACOS_DRAG, GdkMacosDragClass))
+
+typedef struct _GdkMacosDrag GdkMacosDrag;
+typedef struct _GdkMacosDragClass GdkMacosDragClass;
+
+struct _GdkMacosDrag
+{
+ GdkDrag parent_instance;
+
+ GdkMacosDragSurface *drag_surface;
+ GdkSeat *drag_seat;
+ GdkCursor *cursor;
+
+ int hot_x;
+ int hot_y;
+
+ int last_x;
+ int last_y;
+
+ int start_x;
+ int start_y;
+
+ guint did_update : 1;
+ guint cancelled : 1;
+};
+
+struct _GdkMacosDragClass
+{
+ GdkDragClass parent_class;
+};
+
+GType gdk_macos_drag_get_type (void) G_GNUC_CONST;
+gboolean _gdk_macos_drag_begin (GdkMacosDrag *self);
+
+G_END_DECLS
+
+#endif /* __GDK_MACOS_DRAG_PRIVATE_H__ */
--- /dev/null
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#include "gdkdeviceprivate.h"
+#include "gdkintl.h"
+
+#include "gdkmacoscursor-private.h"
+#include "gdkmacosdisplay-private.h"
+#include "gdkmacosdrag-private.h"
+#include "gdkmacosdragsurface-private.h"
+
+#define BIG_STEP 20
+#define SMALL_STEP 1
+#define ANIM_TIME 500000 /* .5 seconds */
+
+typedef struct
+{
+ GdkMacosDrag *drag;
+ GdkFrameClock *frame_clock;
+ gint64 start_time;
+} GdkMacosZoomback;
+
+G_DEFINE_TYPE (GdkMacosDrag, gdk_macos_drag, GDK_TYPE_DRAG)
+
+enum {
+ PROP_0,
+ PROP_DRAG_SURFACE,
+ N_PROPS
+};
+
+static GParamSpec *properties [N_PROPS];
+
+static double
+ease_out_cubic (double t)
+{
+ double p = t - 1;
+ return p * p * p + 1;
+}
+
+static void
+gdk_macos_zoomback_destroy (GdkMacosZoomback *zb)
+{
+ gdk_surface_hide (GDK_SURFACE (zb->drag->drag_surface));
+ g_clear_object (&zb->drag);
+ g_slice_free (GdkMacosZoomback, zb);
+}
+
+static gboolean
+gdk_macos_zoomback_timeout (gpointer data)
+{
+ GdkMacosZoomback *zb = data;
+ GdkFrameClock *frame_clock;
+ GdkMacosDrag *drag;
+ gint64 current_time;
+ double f;
+ double t;
+
+ g_assert (zb != NULL);
+ g_assert (GDK_IS_MACOS_DRAG (zb->drag));
+
+ drag = zb->drag;
+ frame_clock = zb->frame_clock;
+
+ if (!frame_clock)
+ return G_SOURCE_REMOVE;
+
+ current_time = gdk_frame_clock_get_frame_time (frame_clock);
+ f = (current_time - zb->start_time) / (double) ANIM_TIME;
+ if (f >= 1.0)
+ return G_SOURCE_REMOVE;
+
+ t = ease_out_cubic (f);
+
+ _gdk_macos_surface_move (GDK_MACOS_SURFACE (drag->drag_surface),
+ (drag->last_x - drag->hot_x) +
+ (drag->start_x - drag->last_x) * t,
+ (drag->last_y - drag->hot_y) +
+ (drag->start_y - drag->last_y) * t);
+ _gdk_macos_surface_set_opacity (GDK_MACOS_SURFACE (drag->drag_surface), 1.0 - f);
+
+ /* Make sure we're topmost */
+ _gdk_macos_surface_show (GDK_MACOS_SURFACE (drag->drag_surface));
+
+ return G_SOURCE_CONTINUE;
+}
+
+static GdkSurface *
+gdk_macos_drag_get_drag_surface (GdkDrag *drag)
+{
+ return GDK_SURFACE (GDK_MACOS_DRAG (drag)->drag_surface);
+}
+
+static void
+gdk_macos_drag_set_hotspot (GdkDrag *drag,
+ int hot_x,
+ int hot_y)
+{
+ GdkMacosDrag *self = (GdkMacosDrag *)drag;
+ int change_x;
+ int change_y;
+
+ g_assert (GDK_IS_MACOS_DRAG (self));
+
+ change_x = hot_x - self->hot_x;
+ change_y = hot_y - self->hot_y;
+
+ self->hot_x = hot_x;
+ self->hot_y = hot_y;
+
+ if (change_x || change_y)
+ _gdk_macos_surface_move (GDK_MACOS_SURFACE (self->drag_surface),
+ GDK_SURFACE (self->drag_surface)->x + change_x,
+ GDK_SURFACE (self->drag_surface)->y + change_y);
+}
+
+static void
+gdk_macos_drag_drop_done (GdkDrag *drag,
+ gboolean success)
+{
+ GdkMacosDrag *self = (GdkMacosDrag *)drag;
+ GdkMacosZoomback *zb;
+ guint id;
+
+ g_assert (GDK_IS_MACOS_DRAG (self));
+
+ if (success)
+ {
+ gdk_surface_hide (GDK_SURFACE (self->drag_surface));
+ g_object_unref (drag);
+ return;
+ }
+
+ /* Apple HIG suggests doing a "zoomback" animation of the surface back
+ * towards the original position.
+ */
+ zb = g_slice_new0 (GdkMacosZoomback);
+ zb->drag = g_object_ref (self);
+ zb->frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self->drag_surface));
+ zb->start_time = gdk_frame_clock_get_frame_time (zb->frame_clock);
+
+ id = g_timeout_add_full (G_PRIORITY_DEFAULT, 17,
+ gdk_macos_zoomback_timeout,
+ zb,
+ (GDestroyNotify) gdk_macos_zoomback_destroy);
+ g_source_set_name_by_id (id, "[gtk] gdk_macos_zoomback_timeout");
+ g_object_unref (drag);
+}
+
+static void
+gdk_macos_drag_set_cursor (GdkDrag *drag,
+ GdkCursor *cursor)
+{
+ GdkMacosDrag *self = (GdkMacosDrag *)drag;
+ NSCursor *nscursor;
+
+ g_assert (GDK_IS_MACOS_DRAG (self));
+ g_assert (!cursor || GDK_IS_CURSOR (cursor));
+
+ g_set_object (&self->cursor, cursor);
+
+ nscursor = _gdk_macos_cursor_get_ns_cursor (cursor);
+
+ if (nscursor != NULL)
+ [nscursor set];
+}
+
+static gboolean
+drag_grab (GdkMacosDrag *self)
+{
+ GdkSeat *seat;
+
+ g_assert (GDK_IS_MACOS_DRAG (self));
+
+ seat = gdk_device_get_seat (gdk_drag_get_device (GDK_DRAG (self)));
+
+ if (gdk_seat_grab (seat,
+ GDK_SURFACE (self->drag_surface),
+ GDK_SEAT_CAPABILITY_ALL_POINTING,
+ FALSE,
+ self->cursor,
+ NULL,
+ NULL,
+ NULL) != GDK_GRAB_SUCCESS)
+ return FALSE;
+
+ g_set_object (&self->drag_seat, seat);
+
+ return TRUE;
+}
+
+static void
+drag_ungrab (GdkMacosDrag *self)
+{
+ GdkDisplay *display;
+
+ g_assert (GDK_IS_MACOS_DRAG (self));
+
+ display = gdk_drag_get_display (GDK_DRAG (self));
+ _gdk_macos_display_break_all_grabs (GDK_MACOS_DISPLAY (display), GDK_CURRENT_TIME);
+}
+
+static void
+gdk_macos_drag_cancel (GdkDrag *drag,
+ GdkDragCancelReason reason)
+{
+ GdkMacosDrag *self = (GdkMacosDrag *)drag;
+
+ g_assert (GDK_IS_MACOS_DRAG (self));
+
+ if (self->cancelled)
+ return;
+
+ self->cancelled = TRUE;
+ drag_ungrab (self);
+ gdk_drag_drop_done (drag, FALSE);
+}
+
+static void
+gdk_macos_drag_drop_performed (GdkDrag *drag,
+ guint32 time)
+{
+ GdkMacosDrag *self = (GdkMacosDrag *)drag;
+
+ g_assert (GDK_IS_MACOS_DRAG (self));
+
+ drag_ungrab (self);
+ g_signal_emit_by_name (drag, "dnd-finished");
+ gdk_drag_drop_done (drag, TRUE);
+}
+
+static void
+gdk_drag_get_current_actions (GdkModifierType state,
+ gint button,
+ GdkDragAction actions,
+ GdkDragAction *suggested_action,
+ GdkDragAction *possible_actions)
+{
+ *suggested_action = 0;
+ *possible_actions = 0;
+
+ if ((button == GDK_BUTTON_MIDDLE || button == GDK_BUTTON_SECONDARY) && (actions & GDK_ACTION_ASK))
+ {
+ *suggested_action = GDK_ACTION_ASK;
+ *possible_actions = actions;
+ }
+ else if (state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK))
+ {
+ if ((state & GDK_SHIFT_MASK) && (state & GDK_CONTROL_MASK))
+ {
+ if (actions & GDK_ACTION_LINK)
+ {
+ *suggested_action = GDK_ACTION_LINK;
+ *possible_actions = GDK_ACTION_LINK;
+ }
+ }
+ else if (state & GDK_CONTROL_MASK)
+ {
+ if (actions & GDK_ACTION_COPY)
+ {
+ *suggested_action = GDK_ACTION_COPY;
+ *possible_actions = GDK_ACTION_COPY;
+ }
+ }
+ else
+ {
+ if (actions & GDK_ACTION_MOVE)
+ {
+ *suggested_action = GDK_ACTION_MOVE;
+ *possible_actions = GDK_ACTION_MOVE;
+ }
+ }
+ }
+ else
+ {
+ *possible_actions = actions;
+
+ if ((state & (GDK_ALT_MASK)) && (actions & GDK_ACTION_ASK))
+ *suggested_action = GDK_ACTION_ASK;
+ else if (actions & GDK_ACTION_COPY)
+ *suggested_action = GDK_ACTION_COPY;
+ else if (actions & GDK_ACTION_MOVE)
+ *suggested_action = GDK_ACTION_MOVE;
+ else if (actions & GDK_ACTION_LINK)
+ *suggested_action = GDK_ACTION_LINK;
+ }
+}
+
+static void
+gdk_drag_update (GdkDrag *drag,
+ gdouble x_root,
+ gdouble y_root,
+ GdkModifierType mods,
+ guint32 evtime)
+{
+ GdkMacosDrag *self = (GdkMacosDrag *)drag;
+ GdkDragAction suggested_action;
+ GdkDragAction possible_actions;
+
+ g_assert (GDK_IS_MACOS_DRAG (self));
+
+ self->last_x = x_root;
+ self->last_y = y_root;
+
+ gdk_drag_get_current_actions (mods,
+ GDK_BUTTON_PRIMARY,
+ gdk_drag_get_actions (drag),
+ &suggested_action,
+ &possible_actions);
+
+ _gdk_macos_drag_surface_drag_motion (self->drag_surface,
+ x_root - self->hot_x,
+ y_root - self->hot_y,
+ suggested_action,
+ possible_actions,
+ evtime);
+
+ if (!self->did_update)
+ {
+ self->start_x = self->last_x;
+ self->start_y = self->last_y;
+ self->did_update = TRUE;
+ }
+}
+
+static gboolean
+gdk_dnd_handle_motion_event (GdkDrag *drag,
+ GdkEvent *event)
+{
+ double x, y;
+ int x_root, y_root;
+
+ g_assert (GDK_IS_MACOS_DRAG (drag));
+ g_assert (event != NULL);
+
+ /* Ignore motion while doing zoomback */
+ if (GDK_MACOS_DRAG (drag)->cancelled)
+ return FALSE;
+
+ gdk_event_get_position (event, &x, &y);
+ x_root = event->surface->x + x;
+ y_root = event->surface->y + y;
+ gdk_drag_update (drag, x_root, y_root,
+ gdk_event_get_modifier_state (event),
+ gdk_event_get_time (event));
+
+ return TRUE;
+}
+
+static gboolean
+gdk_dnd_handle_grab_broken_event (GdkDrag *drag,
+ GdkEvent *event)
+{
+ GdkMacosDrag *self = GDK_MACOS_DRAG (drag);
+ gboolean is_implicit = gdk_grab_broken_event_get_implicit (event);
+ GdkSurface *grab_surface = gdk_grab_broken_event_get_grab_surface (event);
+
+ /* Don't cancel if we break the implicit grab from the initial button_press. */
+ if (is_implicit || grab_surface == (GdkSurface *)self->drag_surface)
+ return FALSE;
+
+ if (gdk_event_get_device (event) != gdk_drag_get_device (drag))
+ return FALSE;
+
+ gdk_drag_cancel (drag, GDK_DRAG_CANCEL_ERROR);
+
+ return TRUE;
+}
+
+static gboolean
+gdk_dnd_handle_button_event (GdkDrag *drag,
+ GdkEvent *event)
+{
+ GdkMacosDrag *self = GDK_MACOS_DRAG (drag);
+
+ g_assert (GDK_IS_MACOS_DRAG (self));
+ g_assert (event != NULL);
+
+#if 0
+ /* FIXME: Check the button matches */
+ if (event->button != self->button)
+ return FALSE;
+#endif
+
+ if (gdk_drag_get_selected_action (drag) != 0)
+ g_signal_emit_by_name (drag, "drop-performed");
+ else
+ gdk_drag_cancel (drag, GDK_DRAG_CANCEL_NO_TARGET);
+
+ return TRUE;
+}
+
+static gboolean
+gdk_dnd_handle_key_event (GdkDrag *drag,
+ GdkEvent *event)
+{
+ GdkMacosDrag *self = GDK_MACOS_DRAG (drag);
+ GdkModifierType state;
+ GdkDevice *pointer;
+ gint dx, dy;
+
+ dx = dy = 0;
+ state = gdk_event_get_modifier_state (event);
+ pointer = gdk_device_get_associated_device (gdk_event_get_device (event));
+
+ if (event->event_type == GDK_KEY_PRESS)
+ {
+ guint keyval = gdk_key_event_get_keyval (event);
+
+ switch (keyval)
+ {
+ case GDK_KEY_Escape:
+ gdk_drag_cancel (drag, GDK_DRAG_CANCEL_USER_CANCELLED);
+ return TRUE;
+
+ case GDK_KEY_space:
+ case GDK_KEY_Return:
+ case GDK_KEY_ISO_Enter:
+ case GDK_KEY_KP_Enter:
+ case GDK_KEY_KP_Space:
+ if (gdk_drag_get_selected_action (drag) != 0)
+ g_signal_emit_by_name (drag, "drop-performed");
+ else
+ gdk_drag_cancel (drag, GDK_DRAG_CANCEL_NO_TARGET);
+
+ return TRUE;
+
+ case GDK_KEY_Up:
+ case GDK_KEY_KP_Up:
+ dy = (state & GDK_ALT_MASK) ? -BIG_STEP : -SMALL_STEP;
+ break;
+
+ case GDK_KEY_Down:
+ case GDK_KEY_KP_Down:
+ dy = (state & GDK_ALT_MASK) ? BIG_STEP : SMALL_STEP;
+ break;
+
+ case GDK_KEY_Left:
+ case GDK_KEY_KP_Left:
+ dx = (state & GDK_ALT_MASK) ? -BIG_STEP : -SMALL_STEP;
+ break;
+
+ case GDK_KEY_Right:
+ case GDK_KEY_KP_Right:
+ dx = (state & GDK_ALT_MASK) ? BIG_STEP : SMALL_STEP;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ /* The state is not yet updated in the event, so we need
+ * to query it here. We could use XGetModifierMapping, but
+ * that would be overkill.
+ */
+ _gdk_device_query_state (pointer, NULL, NULL, NULL, NULL, &state);
+
+ if (dx != 0 || dy != 0)
+ {
+ GdkDisplay *display = gdk_event_get_display ((GdkEvent *)event);
+
+ self->last_x += dx;
+ self->last_y += dy;
+
+ _gdk_macos_display_warp_pointer (GDK_MACOS_DISPLAY (display),
+ self->last_x,
+ self->last_y);
+ }
+
+ gdk_drag_update (drag,
+ self->last_x, self->last_y,
+ state,
+ gdk_event_get_time (event));
+
+ return TRUE;
+}
+
+static gboolean
+gdk_macos_drag_handle_event (GdkDrag *drag,
+ GdkEvent *event)
+{
+ g_assert (GDK_IS_MACOS_DRAG (drag));
+ g_assert (event != NULL);
+
+ switch ((guint) event->event_type)
+ {
+ case GDK_MOTION_NOTIFY:
+ return gdk_dnd_handle_motion_event (drag, event);
+
+ case GDK_BUTTON_RELEASE:
+ return gdk_dnd_handle_button_event (drag, event);
+
+ case GDK_KEY_PRESS:
+ case GDK_KEY_RELEASE:
+ return gdk_dnd_handle_key_event (drag, event);
+
+ case GDK_GRAB_BROKEN:
+ return gdk_dnd_handle_grab_broken_event (drag, event);
+
+ default:
+ return FALSE;
+ }
+}
+
+static void
+gdk_macos_drag_finalize (GObject *object)
+{
+ GdkMacosDrag *self = (GdkMacosDrag *)object;
+ GdkMacosDragSurface *drag_surface = g_steal_pointer (&self->drag_surface);
+
+ g_clear_object (&self->cursor);
+ g_clear_object (&self->drag_seat);
+
+ G_OBJECT_CLASS (gdk_macos_drag_parent_class)->finalize (object);
+
+ if (drag_surface)
+ gdk_surface_destroy (GDK_SURFACE (drag_surface));
+}
+
+static void
+gdk_macos_drag_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdkMacosDrag *self = GDK_MACOS_DRAG (object);
+
+ switch (prop_id)
+ {
+ case PROP_DRAG_SURFACE:
+ g_value_set_object (value, self->drag_surface);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gdk_macos_drag_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdkMacosDrag *self = GDK_MACOS_DRAG (object);
+
+ switch (prop_id)
+ {
+ case PROP_DRAG_SURFACE:
+ self->drag_surface = g_value_dup_object (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gdk_macos_drag_class_init (GdkMacosDragClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GdkDragClass *drag_class = GDK_DRAG_CLASS (klass);
+
+ object_class->finalize = gdk_macos_drag_finalize;
+ object_class->get_property = gdk_macos_drag_get_property;
+ object_class->set_property = gdk_macos_drag_set_property;
+
+ drag_class->get_drag_surface = gdk_macos_drag_get_drag_surface;
+ drag_class->set_hotspot = gdk_macos_drag_set_hotspot;
+ drag_class->drop_done = gdk_macos_drag_drop_done;
+ drag_class->set_cursor = gdk_macos_drag_set_cursor;
+ drag_class->cancel = gdk_macos_drag_cancel;
+ drag_class->drop_performed = gdk_macos_drag_drop_performed;
+ drag_class->handle_event = gdk_macos_drag_handle_event;
+
+ properties [PROP_DRAG_SURFACE] =
+ g_param_spec_object ("drag-surface",
+ P_("Drag Surface"),
+ P_("Drag Surface"),
+ GDK_TYPE_MACOS_DRAG_SURFACE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+static void
+gdk_macos_drag_init (GdkMacosDrag *self)
+{
+}
+
+gboolean
+_gdk_macos_drag_begin (GdkMacosDrag *self)
+{
+ g_return_val_if_fail (GDK_IS_MACOS_DRAG (self), FALSE);
+
+ _gdk_macos_surface_show (GDK_MACOS_SURFACE (self->drag_surface));
+
+ return drag_grab (self);
+}
--- /dev/null
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef __GDK_MACOS_DRAG_SURFACE_PRIVATE_H__
+#define __GDK_MACOS_DRAG_SURFACE_PRIVATE_H__
+
+#include "gdkmacossurface-private.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GdkMacosDragSurface GdkMacosDragSurface;
+typedef struct _GdkMacosDragSurfaceClass GdkMacosDragSurfaceClass;
+
+#define GDK_TYPE_MACOS_DRAG_SURFACE (_gdk_macos_drag_surface_get_type())
+#define GDK_MACOS_DRAG_SURFACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_MACOS_DRAG_SURFACE, GdkMacosDragSurface))
+#define GDK_IS_MACOS_DRAG_SURFACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MACOS_DRAG_SURFACE))
+
+GType _gdk_macos_drag_surface_get_type (void);
+GdkMacosSurface *_gdk_macos_drag_surface_new (GdkMacosDisplay *display,
+ GdkFrameClock *frame_clock,
+ int x,
+ int y,
+ int width,
+ int height);
+void _gdk_macos_drag_surface_drag_motion (GdkMacosDragSurface *self,
+ int x_root,
+ int y_root,
+ GdkDragAction suggested_action,
+ GdkDragAction possible_actions,
+ guint32 evtime);
+
+G_END_DECLS
+
+#endif /* __GDK_MACOS_DRAG_SURFACE_PRIVATE_H__ */
--- /dev/null
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#include "gdkdragsurfaceprivate.h"
+
+#include "gdkmacosdragsurface-private.h"
+#include "gdkmacosdisplay-private.h"
+#include "gdkmacosutils-private.h"
+
+struct _GdkMacosDragSurface
+{
+ GdkMacosSurface parent_instance;
+};
+
+struct _GdkMacosDragSurfaceClass
+{
+ GdkMacosSurfaceClass parent_instance;
+};
+
+static gboolean
+_gdk_macos_drag_surface_present (GdkDragSurface *surface,
+ int width,
+ int height)
+{
+ g_assert (GDK_IS_MACOS_SURFACE (surface));
+
+ _gdk_macos_surface_move_resize (GDK_MACOS_SURFACE (surface),
+ -1, -1,
+ width, height);
+
+ if (!GDK_SURFACE_IS_MAPPED (GDK_SURFACE (surface)))
+ _gdk_macos_surface_show (GDK_MACOS_SURFACE (surface));
+
+ return GDK_SURFACE_IS_MAPPED (GDK_SURFACE (surface));
+}
+
+static void
+drag_surface_iface_init (GdkDragSurfaceInterface *iface)
+{
+ iface->present = _gdk_macos_drag_surface_present;
+}
+
+G_DEFINE_TYPE_WITH_CODE (GdkMacosDragSurface, _gdk_macos_drag_surface, GDK_TYPE_MACOS_SURFACE,
+ G_IMPLEMENT_INTERFACE (GDK_TYPE_DRAG_SURFACE, drag_surface_iface_init))
+
+static void
+_gdk_macos_drag_surface_class_init (GdkMacosDragSurfaceClass *klass)
+{
+}
+
+static void
+_gdk_macos_drag_surface_init (GdkMacosDragSurface *self)
+{
+}
+
+GdkMacosSurface *
+_gdk_macos_drag_surface_new (GdkMacosDisplay *display,
+ GdkFrameClock *frame_clock,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ GDK_BEGIN_MACOS_ALLOC_POOL;
+
+ GdkMacosWindow *window;
+ GdkMacosSurface *self;
+ NSScreen *screen;
+ NSUInteger style_mask;
+ NSRect content_rect;
+ NSRect screen_rect;
+ int nx;
+ int ny;
+
+ g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (display), NULL);
+ g_return_val_if_fail (!frame_clock || GDK_IS_FRAME_CLOCK (frame_clock), NULL);
+
+ style_mask = NSWindowStyleMaskBorderless;
+
+ _gdk_macos_display_to_display_coords (display, x, y, &nx, &ny);
+
+ screen = _gdk_macos_display_get_screen_at_display_coords (display, nx, ny);
+ screen_rect = [screen frame];
+ nx -= screen_rect.origin.x;
+ ny -= screen_rect.origin.y;
+ content_rect = NSMakeRect (nx, ny - height, width, height);
+
+ window = [[GdkMacosWindow alloc] initWithContentRect:content_rect
+ styleMask:style_mask
+ backing:NSBackingStoreBuffered
+ defer:NO
+ screen:screen];
+
+ [window setOpaque:NO];
+ [window setBackgroundColor:[NSColor clearColor]];
+ [window setDecorated:NO];
+
+ self = g_object_new (GDK_TYPE_MACOS_DRAG_SURFACE,
+ "display", display,
+ "frame-clock", frame_clock,
+ "native", window,
+ NULL);
+
+ GDK_END_MACOS_ALLOC_POOL;
+
+ return g_steal_pointer (&self);
+}
+
+void
+_gdk_macos_drag_surface_drag_motion (GdkMacosDragSurface *self,
+ int x_root,
+ int y_root,
+ GdkDragAction suggested_action,
+ GdkDragAction possible_actions,
+ guint32 evtime)
+{
+ g_return_if_fail (GDK_IS_MACOS_DRAG_SURFACE (self));
+
+ _gdk_macos_surface_move (GDK_MACOS_SURFACE (self), x_root, y_root);
+}
--- /dev/null
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef __GDK_MACOS_EVENT_SOURCE_PRIVATE_H__
+#define __GDK_MACOS_EVENT_SOURCE_PRIVATE_H__
+
+#include <AppKit/AppKit.h>
+
+#include "gdkmacosdisplay.h"
+
+G_BEGIN_DECLS
+
+typedef enum
+{
+ GDK_MACOS_EVENT_SUBTYPE_EVENTLOOP,
+} GdkMacosEventSubType;
+
+GSource *_gdk_macos_event_source_new (GdkMacosDisplay *display);
+NSEvent *_gdk_macos_event_source_get_pending (void);
+gboolean _gdk_macos_event_source_check_pending (void);
+
+G_END_DECLS
+
+#endif /* __GDK_MACOS_EVENT_SOURCE_PRIVATE_H__ */
--- /dev/null
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Copyright (C) 2005-2007 Imendio AB
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+
+#include "gdkdisplayprivate.h"
+#include "gdkinternals.h"
+
+#include "gdkmacoseventsource-private.h"
+#include "gdkmacosdisplay-private.h"
+
+/*
+ * This file implementations integration between the GLib main loop and
+ * the native system of the Core Foundation run loop and Cocoa event
+ * handling. There are basically two different cases that we need to
+ * handle: either the GLib main loop is in control (the application
+ * has called gtk_main(), or is otherwise iterating the main loop), or
+ * CFRunLoop is in control (we are in a modal operation such as window
+ * resizing or drag-and-drop.)
+ *
+ * When the GLib main loop is in control we integrate in native event
+ * handling in two ways: first we add a GSource that handles checking
+ * whether there are native events available, translating native events
+ * to GDK events, and dispatching GDK events. Second we replace the
+ * "poll function" of the GLib main loop with our own version that knows
+ * how to wait for both the file descriptors and timeouts that GLib is
+ * interested in and also for incoming native events.
+ *
+ * When CFRunLoop is in control, we integrate in GLib main loop handling
+ * by adding a "run loop observer" that gives us notification at various
+ * points in the run loop cycle. We map these points onto the corresponding
+ * stages of the GLib main loop (prepare, check, dispatch), and make the
+ * appropriate calls into GLib.
+ *
+ * Both cases share a single problem: the OS X API’s don’t allow us to
+ * wait simultaneously for file descriptors and for events. So when we
+ * need to do a blocking wait that includes file descriptor activity, we
+ * push the actual work of calling select() to a helper thread (the
+ * "select thread") and wait for native events in the main thread.
+ *
+ * The main known limitation of this code is that if a callback is triggered
+ * via the OS X run loop while we are "polling" (in either case described
+ * above), iteration of the GLib main loop is not possible from within
+ * that callback. If the programmer tries to do so explicitly, then they
+ * will get a warning from GLib "main loop already active in another thread".
+ */
+
+/******* State for run loop iteration *******/
+
+/* Count of number of times we've gotten an "Entry" notification for
+ * our run loop observer.
+ */
+static int current_loop_level = 0;
+
+/* Run loop level at which we acquired ownership of the GLib main
+ * loop. See note in run_loop_entry(). -1 means that we don’t have
+ * ownership
+ */
+static int acquired_loop_level = -1;
+
+/* Between run_loop_before_waiting() and run_loop_after_waiting();
+ * whether we we need to call select_thread_collect_poll()
+ */
+static gboolean run_loop_polling_async = FALSE;
+
+/* Between run_loop_before_waiting() and run_loop_after_waiting();
+ * max_prioritiy to pass to g_main_loop_check()
+ */
+static gint run_loop_max_priority;
+
+/* Timer that we've added to wake up the run loop when a GLib timeout
+ */
+static CFRunLoopTimerRef run_loop_timer = NULL;
+
+/* These are the file descriptors that are we are polling out of
+ * the run loop. (We keep the array around and reuse it to avoid
+ * constant allocations.)
+ */
+#define RUN_LOOP_POLLFDS_INITIAL_SIZE 16
+static GPollFD *run_loop_pollfds;
+static guint run_loop_pollfds_size; /* Allocated size of the array */
+static guint run_loop_n_pollfds; /* Number of file descriptors in the array */
+
+/******* Other global variables *******/
+
+/* Since we count on replacing the GLib main loop poll function as our
+ * method of integrating Cocoa event handling into the GLib main loop
+ * we need to make sure that the poll function is always called even
+ * when there are no file descriptors that need to be polled. To do
+ * this, we add a dummy GPollFD to our event source with a file
+ * descriptor of “-1”. Then any time that GLib is polling the event
+ * source, it will call our poll function.
+ */
+static GPollFD event_poll_fd;
+
+/* Current NSEvents that we've gotten from Cocoa but haven't yet converted
+ * to GdkEvents. We wait until our dispatch() function to do the conversion
+ * since the conversion can conceivably cause signals to be emmitted
+ * or other things that shouldn’t happen inside a poll function.
+ */
+static GQueue *current_events;
+
+/* The default poll function for GLib; we replace this with our own
+ * Cocoa-aware version and then call the old version to do actual
+ * file descriptor polling. There’s no actual need to chain to the
+ * old one; we could reimplement the same functionality from scratch,
+ * but since the default implementation does the right thing, why
+ * bother.
+ */
+static GPollFunc old_poll_func;
+
+/* Reference to the run loop of the main thread. (There is a unique
+ * CFRunLoop per thread.)
+ */
+static CFRunLoopRef main_thread_run_loop;
+
+/* Normally the Cocoa main loop maintains an NSAutoReleasePool and frees
+ * it on every iteration. Since we are replacing the main loop we have
+ * to provide this functionality ourself. We free and replace the
+ * auto-release pool in our sources prepare() function.
+ */
+static NSAutoreleasePool *autorelease_pool;
+
+/* Flag when we've called nextEventMatchingMask ourself; this triggers
+ * a run loop iteration, so we need to detect that and avoid triggering
+ * our "run the GLib main looop while the run loop is active machinery.
+ */
+static gint getting_events = 0;
+
+/************************************************************
+ ********* Select Thread *********
+ ************************************************************/
+
+/* The states in our state machine, see comments in select_thread_func()
+ * for descriptiions of each state
+ */
+typedef enum {
+ BEFORE_START,
+ WAITING,
+ POLLING_QUEUED,
+ POLLING_RESTART,
+ POLLING_DESCRIPTORS,
+} SelectThreadState;
+
+#ifdef G_ENABLE_DEBUG
+static const char *const state_names[] = {
+ "BEFORE_START",
+ "WAITING",
+ "POLLING_QUEUED",
+ "POLLING_RESTART",
+ "POLLING_DESCRIPTORS"
+};
+#endif
+
+static SelectThreadState select_thread_state = BEFORE_START;
+
+static pthread_t select_thread;
+static pthread_mutex_t select_thread_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t select_thread_cond = PTHREAD_COND_INITIALIZER;
+
+#define SELECT_THREAD_LOCK() pthread_mutex_lock (&select_thread_mutex)
+#define SELECT_THREAD_UNLOCK() pthread_mutex_unlock (&select_thread_mutex)
+#define SELECT_THREAD_SIGNAL() pthread_cond_signal (&select_thread_cond)
+#define SELECT_THREAD_WAIT() pthread_cond_wait (&select_thread_cond, &select_thread_mutex)
+
+/* These are the file descriptors that the select thread is currently
+ * polling.
+ */
+static GPollFD *current_pollfds;
+static guint current_n_pollfds;
+
+/* These are the file descriptors that the select thread should pick
+ * up and start polling when it has a chance.
+ */
+static GPollFD *next_pollfds;
+static guint next_n_pollfds;
+
+/* Pipe used to wake up the select thread */
+static gint select_thread_wakeup_pipe[2];
+
+/* Run loop source used to wake up the main thread */
+static CFRunLoopSourceRef select_main_thread_source;
+
+static void
+select_thread_set_state (SelectThreadState new_state)
+{
+ gboolean old_state;
+
+ if (select_thread_state == new_state)
+ return;
+
+ GDK_NOTE (EVENTLOOP, g_message ("EventLoop: Select thread state: %s => %s", state_names[select_thread_state], state_names[new_state]));
+
+ old_state = select_thread_state;
+ select_thread_state = new_state;
+ if (old_state == WAITING && new_state != WAITING)
+ SELECT_THREAD_SIGNAL ();
+}
+
+static void
+signal_main_thread (void)
+{
+ GDK_NOTE (EVENTLOOP, g_message ("EventLoop: Waking up main thread"));
+
+ /* If we are in nextEventMatchingMask, then we need to make sure an
+ * event gets queued, otherwise it's enough to simply wake up the
+ * main thread run loop
+ */
+ if (!run_loop_polling_async)
+ CFRunLoopSourceSignal (select_main_thread_source);
+
+ /* Don't check for CFRunLoopIsWaiting() here because it causes a
+ * race condition (the loop could go into waiting state right after
+ * we checked).
+ */
+ CFRunLoopWakeUp (main_thread_run_loop);
+}
+
+static void *
+select_thread_func (void *arg)
+{
+ char c;
+
+ SELECT_THREAD_LOCK ();
+
+ while (TRUE)
+ {
+ switch (select_thread_state)
+ {
+ case BEFORE_START:
+ /* The select thread has not been started yet
+ */
+ g_assert_not_reached ();
+
+ case WAITING:
+ /* Waiting for a set of file descriptors to be submitted by the main thread
+ *
+ * => POLLING_QUEUED: main thread thread submits a set of file descriptors
+ */
+ SELECT_THREAD_WAIT ();
+ break;
+
+ case POLLING_QUEUED:
+ /* Waiting for a set of file descriptors to be submitted by the main thread
+ *
+ * => POLLING_DESCRIPTORS: select thread picks up the file descriptors to begin polling
+ */
+ g_free (current_pollfds);
+
+ current_pollfds = next_pollfds;
+ current_n_pollfds = next_n_pollfds;
+
+ next_pollfds = NULL;
+ next_n_pollfds = 0;
+
+ select_thread_set_state (POLLING_DESCRIPTORS);
+ break;
+
+ case POLLING_RESTART:
+ /* Select thread is currently polling a set of file descriptors, main thread has
+ * began a new iteration with the same set of file descriptors. We don't want to
+ * wake the select thread up and wait for it to restart immediately, but to avoid
+ * a race (described below in select_thread_start_polling()) we need to recheck after
+ * polling completes.
+ *
+ * => POLLING_DESCRIPTORS: select completes, main thread rechecks by polling again
+ * => POLLING_QUEUED: main thread submits a new set of file descriptors to be polled
+ */
+ select_thread_set_state (POLLING_DESCRIPTORS);
+ break;
+
+ case POLLING_DESCRIPTORS:
+ /* In the process of polling the file descriptors
+ *
+ * => WAITING: polling completes when a file descriptor becomes active
+ * => POLLING_QUEUED: main thread submits a new set of file descriptors to be polled
+ * => POLLING_RESTART: main thread begins a new iteration with the same set file descriptors
+ */
+ SELECT_THREAD_UNLOCK ();
+ old_poll_func (current_pollfds, current_n_pollfds, -1);
+ SELECT_THREAD_LOCK ();
+
+ read (select_thread_wakeup_pipe[0], &c, 1);
+
+ if (select_thread_state == POLLING_DESCRIPTORS)
+ {
+ signal_main_thread ();
+ select_thread_set_state (WAITING);
+ }
+ break;
+ }
+ }
+}
+
+static void
+got_fd_activity (void *info)
+{
+ NSEvent *event;
+
+ /* Post a message so we'll break out of the message loop */
+ event = [NSEvent otherEventWithType: NSEventTypeApplicationDefined
+ location: NSZeroPoint
+ modifierFlags: 0
+ timestamp: 0
+ windowNumber: 0
+ context: nil
+ subtype: GDK_MACOS_EVENT_SUBTYPE_EVENTLOOP
+ data1: 0
+ data2: 0];
+
+ [NSApp postEvent:event atStart:YES];
+}
+
+static void
+select_thread_start (void)
+{
+ g_return_if_fail (select_thread_state == BEFORE_START);
+
+ pipe (select_thread_wakeup_pipe);
+ fcntl (select_thread_wakeup_pipe[0], F_SETFL, O_NONBLOCK);
+
+ CFRunLoopSourceContext source_context = {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, got_fd_activity };
+ select_main_thread_source = CFRunLoopSourceCreate (NULL, 0, &source_context);
+
+ CFRunLoopAddSource (main_thread_run_loop, select_main_thread_source, kCFRunLoopCommonModes);
+
+ select_thread_state = WAITING;
+
+ while (TRUE)
+ {
+ if (pthread_create (&select_thread, NULL, select_thread_func, NULL) == 0)
+ break;
+
+ g_warning ("Failed to create select thread, sleeping and trying again");
+ sleep (1);
+ }
+}
+
+#ifdef G_ENABLE_DEBUG
+static void
+dump_poll_result (GPollFD *ufds,
+ guint nfds)
+{
+ GString *s;
+ gint i;
+
+ s = g_string_new ("");
+ for (i = 0; i < nfds; i++)
+ {
+ if (ufds[i].fd >= 0 && ufds[i].revents)
+ {
+ g_string_append_printf (s, " %d:", ufds[i].fd);
+ if (ufds[i].revents & G_IO_IN)
+ g_string_append (s, " in");
+ if (ufds[i].revents & G_IO_OUT)
+ g_string_append (s, " out");
+ if (ufds[i].revents & G_IO_PRI)
+ g_string_append (s, " pri");
+ g_string_append (s, "\n");
+ }
+ }
+ g_message ("%s", s->str);
+ g_string_free (s, TRUE);
+}
+#endif
+
+static gboolean
+pollfds_equal (GPollFD *old_pollfds,
+ guint old_n_pollfds,
+ GPollFD *new_pollfds,
+ guint new_n_pollfds)
+{
+ gint i;
+
+ if (old_n_pollfds != new_n_pollfds)
+ return FALSE;
+
+ for (i = 0; i < old_n_pollfds; i++)
+ {
+ if (old_pollfds[i].fd != new_pollfds[i].fd ||
+ old_pollfds[i].events != new_pollfds[i].events)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Begins a polling operation with the specified GPollFD array; the
+ * timeout is used only to tell if the polling operation is blocking
+ * or non-blocking.
+ *
+ * Returns:
+ * -1: No file descriptors ready, began asynchronous poll
+ * 0: No file descriptors ready, asynchronous poll not needed
+ * > 0: Number of file descriptors ready
+ */
+static gint
+select_thread_start_poll (GPollFD *ufds,
+ guint nfds,
+ gint timeout)
+{
+ gint n_ready;
+ gboolean have_new_pollfds = FALSE;
+ gint poll_fd_index = -1;
+ gint i;
+
+ for (i = 0; i < nfds; i++)
+ if (ufds[i].fd == -1)
+ {
+ poll_fd_index = i;
+ break;
+ }
+
+ if (nfds == 0 ||
+ (nfds == 1 && poll_fd_index >= 0))
+ {
+ GDK_NOTE (EVENTLOOP, g_message ("EventLoop: Nothing to poll"));
+ return 0;
+ }
+
+ /* If we went immediately to an async poll, then we might decide to
+ * dispatch idle functions when higher priority file descriptor sources
+ * are ready to be dispatched. So we always need to first check
+ * check synchronously with a timeout of zero, and only when no
+ * sources are immediately ready, go to the asynchronous poll.
+ *
+ * Of course, if the timeout passed in is 0, then the synchronous
+ * check is sufficient and we never need to do the asynchronous poll.
+ */
+ n_ready = old_poll_func (ufds, nfds, 0);
+ if (n_ready > 0 || timeout == 0)
+ {
+#ifdef G_ENABLE_DEBUG
+ if ((_gdk_debug_flags & GDK_DEBUG_EVENTLOOP) && n_ready > 0)
+ {
+ g_message ("EventLoop: Found ready file descriptors before waiting");
+ dump_poll_result (ufds, nfds);
+ }
+#endif
+
+ return n_ready;
+ }
+
+ SELECT_THREAD_LOCK ();
+
+ if (select_thread_state == BEFORE_START)
+ {
+ select_thread_start ();
+ }
+
+ if (select_thread_state == POLLING_QUEUED)
+ {
+ /* If the select thread hasn't picked up the set of file descriptors yet
+ * then we can simply replace an old stale set with a new set.
+ */
+ if (!pollfds_equal (ufds, nfds, next_pollfds, next_n_pollfds - 1))
+ {
+ g_free (next_pollfds);
+ next_pollfds = NULL;
+ next_n_pollfds = 0;
+
+ have_new_pollfds = TRUE;
+ }
+ }
+ else if (select_thread_state == POLLING_RESTART || select_thread_state == POLLING_DESCRIPTORS)
+ {
+ /* If we are already in the process of polling the right set of file descriptors,
+ * there's no need for us to immediately force the select thread to stop polling
+ * and then restart again. And avoiding doing so increases the efficiency considerably
+ * in the common case where we have a set of basically inactive file descriptors that
+ * stay unchanged present as we process many events.
+ *
+ * However, we have to be careful that we don't hit the following race condition
+ * Select Thread Main Thread
+ * ----------------- ---------------
+ * Polling Completes
+ * Reads data or otherwise changes file descriptor state
+ * Checks if polling is current
+ * Does nothing (*)
+ * Releases lock
+ * Acquires lock
+ * Marks polling as complete
+ * Wakes main thread
+ * Receives old stale file descriptor state
+ *
+ * To avoid this, when the new set of poll descriptors is the same as the current
+ * one, we transition to the POLLING_RESTART stage at the point marked (*). When
+ * the select thread wakes up from the poll because a file descriptor is active, if
+ * the state is POLLING_RESTART it immediately begins polling same the file descriptor
+ * set again. This normally will just return the same set of active file descriptors
+ * as the first time, but in sequence described above will properly update the
+ * file descriptor state.
+ *
+ * Special case: this RESTART logic is not needed if the only FD is the internal GLib
+ * "wakeup pipe" that is presented when threads are initialized.
+ *
+ * P.S.: The harm in the above sequence is mostly that sources can be signalled
+ * as ready when they are no longer ready. This may prompt a blocking read
+ * from a file descriptor that hangs.
+ */
+ if (!pollfds_equal (ufds, nfds, current_pollfds, current_n_pollfds - 1))
+ have_new_pollfds = TRUE;
+ else
+ {
+ if (!((nfds == 1 && poll_fd_index < 0 && g_thread_supported ()) ||
+ (nfds == 2 && poll_fd_index >= 0 && g_thread_supported ())))
+ select_thread_set_state (POLLING_RESTART);
+ }
+ }
+ else
+ have_new_pollfds = TRUE;
+
+ if (have_new_pollfds)
+ {
+ GDK_NOTE (EVENTLOOP, g_message ("EventLoop: Submitting a new set of file descriptor to the select thread"));
+
+ g_assert (next_pollfds == NULL);
+
+ next_n_pollfds = nfds + 1;
+ next_pollfds = g_new (GPollFD, nfds + 1);
+ memcpy (next_pollfds, ufds, nfds * sizeof (GPollFD));
+
+ next_pollfds[nfds].fd = select_thread_wakeup_pipe[0];
+ next_pollfds[nfds].events = G_IO_IN;
+
+ if (select_thread_state != POLLING_QUEUED && select_thread_state != WAITING)
+ {
+ if (select_thread_wakeup_pipe[1])
+ {
+ char c = 'A';
+ write (select_thread_wakeup_pipe[1], &c, 1);
+ }
+ }
+
+ select_thread_set_state (POLLING_QUEUED);
+ }
+
+ SELECT_THREAD_UNLOCK ();
+
+ return -1;
+}
+
+/* End an asynchronous polling operation started with
+ * select_thread_collect_poll(). This must be called if and only if
+ * select_thread_start_poll() return -1. The GPollFD array passed
+ * in must be identical to the one passed to select_thread_start_poll().
+ *
+ * The results of the poll are written into the GPollFD array passed in.
+ *
+ * Returns: number of file descriptors ready
+ */
+static int
+select_thread_collect_poll (GPollFD *ufds, guint nfds)
+{
+ gint i;
+ gint n_ready = 0;
+
+ SELECT_THREAD_LOCK ();
+
+ if (select_thread_state == WAITING) /* The poll completed */
+ {
+ for (i = 0; i < nfds; i++)
+ {
+ if (ufds[i].fd == -1)
+ continue;
+
+ g_assert (ufds[i].fd == current_pollfds[i].fd);
+ g_assert (ufds[i].events == current_pollfds[i].events);
+
+ if (current_pollfds[i].revents)
+ {
+ ufds[i].revents = current_pollfds[i].revents;
+ n_ready++;
+ }
+ }
+
+#ifdef G_ENABLE_DEBUG
+ if (_gdk_debug_flags & GDK_DEBUG_EVENTLOOP)
+ {
+ g_message ("EventLoop: Found ready file descriptors after waiting");
+ dump_poll_result (ufds, nfds);
+ }
+#endif
+ }
+
+ SELECT_THREAD_UNLOCK ();
+
+ return n_ready;
+}
+
+/************************************************************
+ ********* Main Loop Source *********
+ ************************************************************/
+
+typedef struct _GdkMacosEventSource
+{
+ GSource source;
+ GdkDisplay *display;
+} GdkMacosEventSource;
+
+gboolean
+_gdk_macos_event_source_check_pending (void)
+{
+ return current_events && current_events->head;
+}
+
+NSEvent *
+_gdk_macos_event_source_get_pending (void)
+{
+ NSEvent *event = NULL;
+
+ if (current_events)
+ event = g_queue_pop_tail (current_events);
+
+ return event;
+}
+
+static gboolean
+gdk_macos_event_source_prepare (GSource *source,
+ gint *timeout)
+{
+ GdkMacosEventSource *event_source = (GdkMacosEventSource *)source;
+ gboolean retval;
+
+ /* The prepare stage is the stage before the main loop starts polling
+ * and dispatching events. The autorelease poll is drained here for
+ * the preceding main loop iteration or, in case of the first iteration,
+ * for the operations carried out between event loop initialization and
+ * this first iteration.
+ *
+ * The autorelease poll must only be drained when the following conditions
+ * apply:
+ * - We are at the base CFRunLoop level (indicated by current_loop_level),
+ * - We are at the base g_main_loop level (indicated by
+ * g_main_depth())
+ * - We are at the base poll_func level (indicated by getting events).
+ *
+ * Messing with the autorelease pool at any level of nesting can cause access
+ * to deallocated memory because autorelease_pool is static and releasing a
+ * pool will cause all pools allocated inside of it to be released as well.
+ */
+ if (current_loop_level == 0 && g_main_depth() == 0 && getting_events == 0)
+ {
+ if (autorelease_pool)
+ [autorelease_pool drain];
+
+ autorelease_pool = [[NSAutoreleasePool alloc] init];
+ }
+
+ *timeout = -1;
+
+ if (event_source->display->event_pause_count > 0)
+ retval = _gdk_event_queue_find_first (event_source->display) != NULL;
+ else
+ retval = (_gdk_event_queue_find_first (event_source->display) != NULL ||
+ _gdk_macos_event_source_check_pending ());
+
+ return retval;
+}
+
+static gboolean
+gdk_macos_event_source_check (GSource *source)
+{
+ GdkMacosEventSource *event_source = (GdkMacosEventSource *)source;
+ gboolean retval;
+
+ if (event_source->display->event_pause_count > 0)
+ retval = _gdk_event_queue_find_first (event_source->display) != NULL;
+ else
+ retval = (_gdk_event_queue_find_first (event_source->display) != NULL ||
+ _gdk_macos_event_source_check_pending ());
+
+ return retval;
+}
+
+static gboolean
+gdk_macos_event_source_dispatch (GSource *source,
+ GSourceFunc callback,
+ gpointer user_data)
+{
+ GdkMacosEventSource *event_source = (GdkMacosEventSource *)source;
+ GdkEvent *event;
+
+ _gdk_macos_display_queue_events (GDK_MACOS_DISPLAY (event_source->display));
+
+ event = _gdk_event_unqueue (event_source->display);
+
+ if (event)
+ {
+ _gdk_event_emit (event);
+
+ gdk_event_unref (event);
+ }
+
+ return TRUE;
+}
+
+static void
+gdk_macos_event_source_finalize (GSource *source)
+{
+ GdkMacosEventSource *event_source = (GdkMacosEventSource *)source;
+
+ g_clear_object (&event_source->display);
+}
+
+static GSourceFuncs event_funcs = {
+ gdk_macos_event_source_prepare,
+ gdk_macos_event_source_check,
+ gdk_macos_event_source_dispatch,
+ gdk_macos_event_source_finalize,
+};
+
+/************************************************************
+ ********* Our Poll Function *********
+ ************************************************************/
+
+static gint
+poll_func (GPollFD *ufds,
+ guint nfds,
+ gint timeout_)
+{
+ NSEvent *event;
+ NSDate *limit_date;
+ gint n_ready;
+
+ static GPollFD *last_ufds;
+
+ last_ufds = ufds;
+
+ n_ready = select_thread_start_poll (ufds, nfds, timeout_);
+ if (n_ready > 0)
+ timeout_ = 0;
+
+ if (timeout_ == -1)
+ limit_date = [NSDate distantFuture];
+ else if (timeout_ == 0)
+ limit_date = [NSDate distantPast];
+ else
+ limit_date = [NSDate dateWithTimeIntervalSinceNow:timeout_/1000.0];
+
+ getting_events++;
+ event = [NSApp nextEventMatchingMask: NSEventMaskAny
+ untilDate: limit_date
+ inMode: NSDefaultRunLoopMode
+ dequeue: YES];
+ getting_events--;
+
+ /* We check if last_ufds did not change since the time this function was
+ * called. It is possible that a recursive main loop (and thus recursive
+ * invocation of this poll function) is triggered while in
+ * nextEventMatchingMask:. If during that time new fds are added,
+ * the cached fds array might be replaced in g_main_context_iterate().
+ * So, we should avoid accessing the old fd array (still pointed at by
+ * ufds) here in that case, since it might have been freed. We avoid this
+ * by not calling the collect stage.
+ */
+ if (last_ufds == ufds && n_ready < 0)
+ n_ready = select_thread_collect_poll (ufds, nfds);
+
+ if (event &&
+ [event type] == NSEventTypeApplicationDefined &&
+ [event subtype] == GDK_MACOS_EVENT_SUBTYPE_EVENTLOOP)
+ {
+ /* Just used to wake us up; if an event and a FD arrived at the same
+ * time; could have come from a previous iteration in some cases,
+ * but the spurious wake up is harmless if a little inefficient.
+ */
+ event = NULL;
+ }
+
+ if (event)
+ {
+ if (!current_events)
+ current_events = g_queue_new ();
+ g_queue_push_head (current_events, [event retain]);
+ }
+
+ return n_ready;
+}
+
+/************************************************************
+ ********* Running the main loop out of CFRunLoop *********
+ ************************************************************/
+
+/* Wrapper around g_main_context_query() that handles reallocating
+ * run_loop_pollfds up to the proper size
+ */
+static gint
+query_main_context (GMainContext *context,
+ int max_priority,
+ int *timeout)
+{
+ gint nfds;
+
+ if (!run_loop_pollfds)
+ {
+ run_loop_pollfds_size = RUN_LOOP_POLLFDS_INITIAL_SIZE;
+ run_loop_pollfds = g_new (GPollFD, run_loop_pollfds_size);
+ }
+
+ while ((nfds = g_main_context_query (context, max_priority, timeout,
+ run_loop_pollfds,
+ run_loop_pollfds_size)) > run_loop_pollfds_size)
+ {
+ g_free (run_loop_pollfds);
+ run_loop_pollfds_size = nfds;
+ run_loop_pollfds = g_new (GPollFD, nfds);
+ }
+
+ return nfds;
+}
+
+static void
+run_loop_entry (void)
+{
+ if (acquired_loop_level == -1)
+ {
+ if (g_main_context_acquire (NULL))
+ {
+ GDK_NOTE (EVENTLOOP, g_message ("EventLoop: Beginning tracking run loop activity"));
+ acquired_loop_level = current_loop_level;
+ }
+ else
+ {
+ /* If we fail to acquire the main context, that means someone is iterating
+ * the main context in a different thread; we simply wait until this loop
+ * exits and then try again at next entry. In general, iterating the loop
+ * from a different thread is rare: it is only possible when GDK threading
+ * is initialized and is not frequently used even then. So, we hope that
+ * having GLib main loop iteration blocked in the combination of that and
+ * a native modal operation is a minimal problem. We could imagine using a
+ * thread that does g_main_context_wait() and then wakes us back up, but
+ * the gain doesn't seem worth the complexity.
+ */
+ GDK_NOTE (EVENTLOOP, g_message ("EventLoop: Can't acquire main loop; skipping tracking run loop activity"));
+ }
+ }
+}
+
+static void
+run_loop_before_timers (void)
+{
+}
+
+static void
+run_loop_before_sources (void)
+{
+ GMainContext *context = g_main_context_default ();
+ gint max_priority;
+ gint nfds;
+
+ /* Before we let the CFRunLoop process sources, we want to check if there
+ * are any pending GLib main loop sources more urgent than
+ * G_PRIORITY_DEFAULT that need to be dispatched. (We consider all activity
+ * from the CFRunLoop to have a priority of G_PRIORITY_DEFAULT.) If no
+ * sources are processed by the CFRunLoop, then processing will continue
+ * on to the BeforeWaiting stage where we check for lower priority sources.
+ */
+
+ g_main_context_prepare (context, &max_priority);
+ max_priority = MIN (max_priority, G_PRIORITY_DEFAULT);
+
+ /* We ignore the timeout that query_main_context () returns since we'll
+ * always query again before waiting.
+ */
+ nfds = query_main_context (context, max_priority, NULL);
+
+ if (nfds)
+ old_poll_func (run_loop_pollfds, nfds, 0);
+
+ if (g_main_context_check (context, max_priority, run_loop_pollfds, nfds))
+ {
+ GDK_NOTE (EVENTLOOP, g_message ("EventLoop: Dispatching high priority sources"));
+ g_main_context_dispatch (context);
+ }
+}
+
+static void
+dummy_timer_callback (CFRunLoopTimerRef timer,
+ void *info)
+{
+ /* Nothing; won't normally even be called */
+}
+
+static void
+run_loop_before_waiting (void)
+{
+ GMainContext *context = g_main_context_default ();
+ gint timeout;
+ gint n_ready;
+
+ /* At this point, the CFRunLoop is ready to wait. We start a GMain loop
+ * iteration by calling the check() and query() stages. We start a
+ * poll, and if it doesn't complete immediately we let the run loop
+ * go ahead and sleep. Before doing that, if there was a timeout from
+ * GLib, we set up a CFRunLoopTimer to wake us up.
+ */
+
+ g_main_context_prepare (context, &run_loop_max_priority);
+
+ run_loop_n_pollfds = query_main_context (context, run_loop_max_priority, &timeout);
+
+ n_ready = select_thread_start_poll (run_loop_pollfds, run_loop_n_pollfds, timeout);
+
+ if (n_ready > 0 || timeout == 0)
+ {
+ /* We have stuff to do, no sleeping allowed! */
+ CFRunLoopWakeUp (main_thread_run_loop);
+ }
+ else if (timeout > 0)
+ {
+ /* We need to get the run loop to break out of its wait when our timeout
+ * expires. We do this by adding a dummy timer that we'll remove immediately
+ * after the wait wakes up.
+ */
+ GDK_NOTE (EVENTLOOP, g_message ("EventLoop: Adding timer to wake us up in %d milliseconds", timeout));
+
+ run_loop_timer = CFRunLoopTimerCreate (NULL, /* allocator */
+ CFAbsoluteTimeGetCurrent () + timeout / 1000.,
+ 0, /* interval (0=does not repeat) */
+ 0, /* flags */
+ 0, /* order (priority) */
+ dummy_timer_callback,
+ NULL);
+
+ CFRunLoopAddTimer (main_thread_run_loop, run_loop_timer, kCFRunLoopCommonModes);
+ }
+
+ run_loop_polling_async = n_ready < 0;
+}
+
+static void
+run_loop_after_waiting (void)
+{
+ GMainContext *context = g_main_context_default ();
+
+ /* After sleeping, we finish of the GMain loop iteratin started in before_waiting()
+ * by doing the check() and dispatch() stages.
+ */
+
+ if (run_loop_timer)
+ {
+ CFRunLoopRemoveTimer (main_thread_run_loop, run_loop_timer, kCFRunLoopCommonModes);
+ CFRelease (run_loop_timer);
+ run_loop_timer = NULL;
+ }
+
+ if (run_loop_polling_async)
+ {
+ select_thread_collect_poll (run_loop_pollfds, run_loop_n_pollfds);
+ run_loop_polling_async = FALSE;
+ }
+
+ if (g_main_context_check (context, run_loop_max_priority, run_loop_pollfds, run_loop_n_pollfds))
+ {
+ GDK_NOTE (EVENTLOOP, g_message ("EventLoop: Dispatching after waiting"));
+ g_main_context_dispatch (context);
+ }
+}
+
+static void
+run_loop_exit (void)
+{
+ /* + 1 because we decrement current_loop_level separately in observer_callback() */
+ if ((current_loop_level + 1) == acquired_loop_level)
+ {
+ g_main_context_release (NULL);
+ acquired_loop_level = -1;
+ GDK_NOTE (EVENTLOOP, g_message ("EventLoop: Ended tracking run loop activity"));
+ }
+}
+
+static void
+run_loop_observer_callback (CFRunLoopObserverRef observer,
+ CFRunLoopActivity activity,
+ void *info)
+{
+ switch (activity)
+ {
+ case kCFRunLoopEntry:
+ current_loop_level++;
+ break;
+ case kCFRunLoopExit:
+ g_return_if_fail (current_loop_level > 0);
+ current_loop_level--;
+ break;
+ case kCFRunLoopBeforeTimers:
+ case kCFRunLoopBeforeSources:
+ case kCFRunLoopBeforeWaiting:
+ case kCFRunLoopAfterWaiting:
+ case kCFRunLoopAllActivities:
+ default:
+ break;
+ }
+
+ if (getting_events > 0) /* Activity we triggered */
+ return;
+
+ switch (activity)
+ {
+ case kCFRunLoopEntry:
+ run_loop_entry ();
+ break;
+ case kCFRunLoopBeforeTimers:
+ run_loop_before_timers ();
+ break;
+ case kCFRunLoopBeforeSources:
+ run_loop_before_sources ();
+ break;
+ case kCFRunLoopBeforeWaiting:
+ run_loop_before_waiting ();
+ break;
+ case kCFRunLoopAfterWaiting:
+ run_loop_after_waiting ();
+ break;
+ case kCFRunLoopExit:
+ run_loop_exit ();
+ break;
+ case kCFRunLoopAllActivities:
+ /* TODO: Do most of the above? */
+ default:
+ break;
+ }
+}
+
+/************************************************************/
+
+GSource *
+_gdk_macos_event_source_new (GdkMacosDisplay *display)
+{
+ CFRunLoopObserverRef observer;
+ GdkMacosEventSource *event_source;
+ GSource *source;
+
+ g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (display), NULL);
+
+ /* Hook into the GLib main loop */
+
+ event_poll_fd.events = G_IO_IN;
+ event_poll_fd.fd = -1;
+
+ source = g_source_new (&event_funcs, sizeof (GdkMacosEventSource));
+ g_source_set_name (source, "GDK Quartz event source");
+ g_source_add_poll (source, &event_poll_fd);
+ g_source_set_priority (source, GDK_PRIORITY_EVENTS);
+ g_source_set_can_recurse (source, TRUE);
+
+ old_poll_func = g_main_context_get_poll_func (NULL);
+ g_main_context_set_poll_func (NULL, poll_func);
+
+ event_source = (GdkMacosEventSource *)source;
+ event_source->display = g_object_ref (GDK_DISPLAY (display));
+
+ /* Hook into the the CFRunLoop for the main thread */
+
+ main_thread_run_loop = CFRunLoopGetCurrent ();
+
+ observer = CFRunLoopObserverCreate (NULL, /* default allocator */
+ kCFRunLoopAllActivities,
+ true, /* repeats: not one-shot */
+ 0, /* order (priority) */
+ run_loop_observer_callback,
+ NULL);
+
+ CFRunLoopAddObserver (main_thread_run_loop, observer, kCFRunLoopCommonModes);
+
+ /* Initialize our autorelease pool */
+ autorelease_pool = [[NSAutoreleasePool alloc] init];
+
+ return source;
+}
--- /dev/null
+/* gdkmacosglcontext-private.h
+ *
+ * Copyright (C) 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GDK_MACOS_GL_CONTEXT_PRIVATE_H__
+#define __GDK_MACOS_GL_CONTEXT_PRIVATE_H__
+
+#include "gdkglcontextprivate.h"
+#include "gdkdisplayprivate.h"
+#include "gdksurface.h"
+#include "gdkinternals.h"
+
+#include "gdkmacosglcontext.h"
+#include "gdkmacossurface.h"
+
+#import <OpenGL/OpenGL.h>
+#import <OpenGL/gl.h>
+#import <AppKit/AppKit.h>
+
+G_BEGIN_DECLS
+
+struct _GdkMacosGLContext
+{
+ GdkGLContext parent_instance;
+
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+ NSOpenGLContext *gl_context;
+ G_GNUC_END_IGNORE_DEPRECATIONS
+
+ gboolean is_attached;
+};
+
+struct _GdkMacosGLContextClass
+{
+ GdkGLContextClass parent_class;
+};
+
+GdkGLContext *_gdk_macos_gl_context_new (GdkMacosSurface *surface,
+ gboolean attached,
+ GdkGLContext *share,
+ GError **error);
+gboolean _gdk_macos_gl_context_make_current (GdkMacosGLContext *self);
+
+G_END_DECLS
+
+#endif /* __GDK_MACOS_GL_CONTEXT_PRIVATE_H__ */
--- /dev/null
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#include "gdkmacosglcontext-private.h"
+#include "gdkmacossurface-private.h"
+
+#include "gdkinternals.h"
+#include "gdkintl.h"
+
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+
+G_DEFINE_TYPE (GdkMacosGLContext, gdk_macos_gl_context, GDK_TYPE_GL_CONTEXT)
+
+static void
+gdk_macos_gl_context_end_frame (GdkDrawContext *context,
+ cairo_region_t *painted)
+{
+ GdkMacosGLContext *self = GDK_MACOS_GL_CONTEXT (context);
+
+ g_assert (GDK_IS_MACOS_GL_CONTEXT (self));
+
+ [self->gl_context flushBuffer];
+}
+
+static void
+gdk_macos_gl_context_dispose (GObject *gobject)
+{
+ GdkMacosGLContext *context_macos = GDK_MACOS_GL_CONTEXT (gobject);
+
+ if (context_macos->gl_context != NULL)
+ {
+ [context_macos->gl_context clearDrawable];
+ [context_macos->gl_context release];
+ context_macos->gl_context = NULL;
+ }
+
+ G_OBJECT_CLASS (gdk_macos_gl_context_parent_class)->dispose (gobject);
+}
+
+static void
+gdk_macos_gl_context_class_init (GdkMacosGLContextClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS (klass);
+
+ object_class->dispose = gdk_macos_gl_context_dispose;
+
+ draw_context_class->end_frame = gdk_macos_gl_context_end_frame;
+}
+
+static void
+gdk_macos_gl_context_init (GdkMacosGLContext *self)
+{
+}
+
+GdkGLContext *
+_gdk_macos_gl_context_new (GdkMacosSurface *surface,
+ gboolean attached,
+ GdkGLContext *share,
+ GError **error)
+{
+ static const NSOpenGLPixelFormatAttribute attrs[] = {
+ NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
+ NSOpenGLPFADoubleBuffer,
+ NSOpenGLPFAColorSize, 24,
+ NSOpenGLPFAAlphaSize, 8,
+ 0
+ };
+
+ NSOpenGLPixelFormat *format;
+ GdkMacosGLContext *context = NULL;
+ NSOpenGLContext *ctx;
+ GdkDisplay *display;
+ NSView *nsview;
+ GLint sync_to_framerate = 1;
+
+ g_return_val_if_fail (GDK_IS_MACOS_SURFACE (surface), NULL);
+ g_return_val_if_fail (!share || GDK_IS_MACOS_GL_CONTEXT (share), NULL);
+
+ display = gdk_surface_get_display (GDK_SURFACE (surface));
+
+ if (!(format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]))
+ {
+ g_set_error_literal (error,
+ GDK_GL_ERROR,
+ GDK_GL_ERROR_NOT_AVAILABLE,
+ _("Unable to create a GL pixel format"));
+ goto failure;
+ }
+
+ ctx = [[NSOpenGLContext alloc] initWithFormat:format
+ shareContext:share ? GDK_MACOS_GL_CONTEXT (share)->gl_context : nil];
+ if (ctx == NULL)
+ {
+ g_set_error_literal (error,
+ GDK_GL_ERROR,
+ GDK_GL_ERROR_NOT_AVAILABLE,
+ _("Unable to create a GL context"));
+ goto failure;
+ }
+
+ nsview = _gdk_macos_surface_get_view (surface);
+ [nsview setWantsBestResolutionOpenGLSurface:YES];
+ [ctx setValues:&sync_to_framerate forParameter:NSOpenGLCPSwapInterval];
+ [ctx setView:nsview];
+
+ GDK_NOTE (OPENGL,
+ g_print ("Created NSOpenGLContext[%p]\n", ctx));
+
+ context = g_object_new (GDK_TYPE_MACOS_GL_CONTEXT,
+ "surface", surface,
+ "shared-context", share,
+ NULL);
+
+ context->gl_context = ctx;
+ context->is_attached = attached;
+
+failure:
+ if (format != NULL)
+ [format release];
+
+ return GDK_GL_CONTEXT (context);
+}
+
+gboolean
+_gdk_macos_gl_context_make_current (GdkMacosGLContext *self)
+{
+ g_return_val_if_fail (GDK_IS_MACOS_GL_CONTEXT (self), FALSE);
+
+ [self->gl_context makeCurrentContext];
+
+ return TRUE;
+}
+
+G_GNUC_END_IGNORE_DEPRECATIONS
--- /dev/null
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef __GDK_MACOS_GL_CONTEXT_H__
+#define __GDK_MACOS_GL_CONTEXT_H__
+
+#if !defined (__GDKMACOS_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gdk/macos/gdkmacos.h> can be included directly."
+#endif
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_MACOS_GL_CONTEXT (gdk_macos_gl_context_get_type ())
+#define GDK_MACOS_GL_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_MACOS_GL_CONTEXT, GdkMacosGLContext))
+#define GDK_IS_MACOS_GL_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_MACOS_GL_CONTEXT))
+
+typedef struct _GdkMacosGLContext GdkMacosGLContext;
+typedef struct _GdkMacosGLContextClass GdkMacosGLContextClass;
+
+GDK_AVAILABLE_IN_ALL
+GType gdk_macos_gl_context_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __GDK_MACOS_GL_CONTEXT_H__ */
--- /dev/null
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef __GDK_MACOS_KEYMAP_PRIVATE_H__
+#define __GDK_MACOS_KEYMAP_PRIVATE_H__
+
+#include <AppKit/AppKit.h>
+
+#include "gdkmacosdisplay.h"
+#include "gdkmacoskeymap.h"
+
+G_BEGIN_DECLS
+
+GdkMacosKeymap *_gdk_macos_keymap_new (GdkMacosDisplay *display);
+GdkEventType _gdk_macos_keymap_get_event_type (NSEvent *event);
+gboolean _gdk_macos_keymap_is_modifier (guint keycode);
+
+G_END_DECLS
+
+#endif /* __GDK_MACOS_KEYMAP_PRIVATE_H__ */
--- /dev/null
+/*
+ * Copyright © 2000-2020 Red Hat, Inc.
+ * Copyright © 2005 Imendio AB
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+/* Some parts of this code come from quartzKeyboard.c,
+ * from the Apple X11 Server.
+ *
+ * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT
+ * HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name(s) of the above
+ * copyright holders shall not be used in advertising or otherwise to
+ * promote the sale, use or other dealings in this Software without
+ * prior written authorization.
+ */
+
+#include "config.h"
+
+#include <AppKit/AppKit.h>
+#include <Carbon/Carbon.h>
+#include <gdk/gdk.h>
+
+#include "gdkkeysprivate.h"
+#include "gdkkeysyms.h"
+#include "gdkmacoskeymap-private.h"
+
+struct _GdkMacosKeymap
+{
+ GdkKeymap parent_instance;
+};
+
+struct _GdkMacosKeymapClass
+{
+ GdkKeymapClass parent_instance;
+};
+
+G_DEFINE_TYPE (GdkMacosKeymap, gdk_macos_keymap, GDK_TYPE_KEYMAP)
+
+/* This is a table of all keyvals. Each keycode gets KEYVALS_PER_KEYCODE entries.
+ * TThere is 1 keyval per modifier (Nothing, Shift, Alt, Shift+Alt);
+ */
+static guint *keyval_array = NULL;
+
+#define NUM_KEYCODES 128
+#define KEYVALS_PER_KEYCODE 4
+#define GET_KEYVAL(keycode, group, level) \
+ (keyval_array[(keycode * KEYVALS_PER_KEYCODE + group * 2 + level)])
+
+const static struct {
+ guint keycode;
+ guint keyval;
+ unsigned int modmask; /* So we can tell when a mod key is pressed/released */
+} modifier_keys[] = {
+ { 54, GDK_KEY_Meta_R, NSEventModifierFlagCommand },
+ { 55, GDK_KEY_Meta_L, NSEventModifierFlagCommand },
+ { 56, GDK_KEY_Shift_L, NSEventModifierFlagShift },
+ { 57, GDK_KEY_Caps_Lock, NSEventModifierFlagCapsLock },
+ { 58, GDK_KEY_Alt_L, NSEventModifierFlagOption },
+ { 59, GDK_KEY_Control_L, NSEventModifierFlagControl },
+ { 60, GDK_KEY_Shift_R, NSEventModifierFlagShift },
+ { 61, GDK_KEY_Alt_R, NSEventModifierFlagOption },
+ { 62, GDK_KEY_Control_R, NSEventModifierFlagControl }
+};
+
+const static struct {
+ guint keycode;
+ guint keyval;
+} function_keys[] = {
+ { 122, GDK_KEY_F1 },
+ { 120, GDK_KEY_F2 },
+ { 99, GDK_KEY_F3 },
+ { 118, GDK_KEY_F4 },
+ { 96, GDK_KEY_F5 },
+ { 97, GDK_KEY_F6 },
+ { 98, GDK_KEY_F7 },
+ { 100, GDK_KEY_F8 },
+ { 101, GDK_KEY_F9 },
+ { 109, GDK_KEY_F10 },
+ { 103, GDK_KEY_F11 },
+ { 111, GDK_KEY_F12 },
+ { 105, GDK_KEY_F13 },
+ { 107, GDK_KEY_F14 },
+ { 113, GDK_KEY_F15 },
+ { 106, GDK_KEY_F16 }
+};
+
+const static struct {
+ guint keycode;
+ guint normal_keyval, keypad_keyval;
+} known_numeric_keys[] = {
+ { 65, GDK_KEY_period, GDK_KEY_KP_Decimal },
+ { 67, GDK_KEY_asterisk, GDK_KEY_KP_Multiply },
+ { 69, GDK_KEY_plus, GDK_KEY_KP_Add },
+ { 75, GDK_KEY_slash, GDK_KEY_KP_Divide },
+ { 76, GDK_KEY_Return, GDK_KEY_KP_Enter },
+ { 78, GDK_KEY_minus, GDK_KEY_KP_Subtract },
+ { 81, GDK_KEY_equal, GDK_KEY_KP_Equal },
+ { 82, GDK_KEY_0, GDK_KEY_KP_0 },
+ { 83, GDK_KEY_1, GDK_KEY_KP_1 },
+ { 84, GDK_KEY_2, GDK_KEY_KP_2 },
+ { 85, GDK_KEY_3, GDK_KEY_KP_3 },
+ { 86, GDK_KEY_4, GDK_KEY_KP_4 },
+ { 87, GDK_KEY_5, GDK_KEY_KP_5 },
+ { 88, GDK_KEY_6, GDK_KEY_KP_6 },
+ { 89, GDK_KEY_7, GDK_KEY_KP_7 },
+ { 91, GDK_KEY_8, GDK_KEY_KP_8 },
+ { 92, GDK_KEY_9, GDK_KEY_KP_9 }
+};
+
+/* These values aren't covered by gdk_unicode_to_keyval */
+const static struct {
+ gunichar ucs_value;
+ guint keyval;
+} special_ucs_table [] = {
+ { 0x0001, GDK_KEY_Home },
+ { 0x0003, GDK_KEY_Return },
+ { 0x0004, GDK_KEY_End },
+ { 0x0008, GDK_KEY_BackSpace },
+ { 0x0009, GDK_KEY_Tab },
+ { 0x000b, GDK_KEY_Page_Up },
+ { 0x000c, GDK_KEY_Page_Down },
+ { 0x000d, GDK_KEY_Return },
+ { 0x001b, GDK_KEY_Escape },
+ { 0x001c, GDK_KEY_Left },
+ { 0x001d, GDK_KEY_Right },
+ { 0x001e, GDK_KEY_Up },
+ { 0x001f, GDK_KEY_Down },
+ { 0x007f, GDK_KEY_Delete },
+ { 0xf027, GDK_KEY_dead_acute },
+ { 0xf060, GDK_KEY_dead_grave },
+ { 0xf300, GDK_KEY_dead_grave },
+ { 0xf0b4, GDK_KEY_dead_acute },
+ { 0xf301, GDK_KEY_dead_acute },
+ { 0xf385, GDK_KEY_dead_acute },
+ { 0xf05e, GDK_KEY_dead_circumflex },
+ { 0xf2c6, GDK_KEY_dead_circumflex },
+ { 0xf302, GDK_KEY_dead_circumflex },
+ { 0xf07e, GDK_KEY_dead_tilde },
+ { 0xf2dc, GDK_KEY_dead_tilde },
+ { 0xf303, GDK_KEY_dead_tilde },
+ { 0xf342, GDK_KEY_dead_perispomeni },
+ { 0xf0af, GDK_KEY_dead_macron },
+ { 0xf304, GDK_KEY_dead_macron },
+ { 0xf2d8, GDK_KEY_dead_breve },
+ { 0xf306, GDK_KEY_dead_breve },
+ { 0xf2d9, GDK_KEY_dead_abovedot },
+ { 0xf307, GDK_KEY_dead_abovedot },
+ { 0xf0a8, GDK_KEY_dead_diaeresis },
+ { 0xf308, GDK_KEY_dead_diaeresis },
+ { 0xf2da, GDK_KEY_dead_abovering },
+ { 0xf30A, GDK_KEY_dead_abovering },
+ { 0xf022, GDK_KEY_dead_doubleacute },
+ { 0xf2dd, GDK_KEY_dead_doubleacute },
+ { 0xf30B, GDK_KEY_dead_doubleacute },
+ { 0xf2c7, GDK_KEY_dead_caron },
+ { 0xf30C, GDK_KEY_dead_caron },
+ { 0xf0be, GDK_KEY_dead_cedilla },
+ { 0xf327, GDK_KEY_dead_cedilla },
+ { 0xf2db, GDK_KEY_dead_ogonek },
+ { 0xf328, GDK_KEY_dead_ogonek },
+ { 0xfe5d, GDK_KEY_dead_iota },
+ { 0xf323, GDK_KEY_dead_belowdot },
+ { 0xf309, GDK_KEY_dead_hook },
+ { 0xf31B, GDK_KEY_dead_horn },
+ { 0xf02d, GDK_KEY_dead_stroke },
+ { 0xf335, GDK_KEY_dead_stroke },
+ { 0xf336, GDK_KEY_dead_stroke },
+ { 0xf313, GDK_KEY_dead_abovecomma },
+ /* { 0xf313, GDK_KEY_dead_psili }, */
+ { 0xf314, GDK_KEY_dead_abovereversedcomma },
+ /* { 0xf314, GDK_KEY_dead_dasia }, */
+ { 0xf30F, GDK_KEY_dead_doublegrave },
+ { 0xf325, GDK_KEY_dead_belowring },
+ { 0xf2cd, GDK_KEY_dead_belowmacron },
+ { 0xf331, GDK_KEY_dead_belowmacron },
+ { 0xf32D, GDK_KEY_dead_belowcircumflex },
+ { 0xf330, GDK_KEY_dead_belowtilde },
+ { 0xf32E, GDK_KEY_dead_belowbreve },
+ { 0xf324, GDK_KEY_dead_belowdiaeresis },
+ { 0xf311, GDK_KEY_dead_invertedbreve },
+ { 0xf02c, GDK_KEY_dead_belowcomma },
+ { 0xf326, GDK_KEY_dead_belowcomma }
+};
+
+static void
+gdk_macos_keymap_update (GdkMacosKeymap *self)
+{
+ const void *chr_data = NULL;
+ guint *p;
+ int i;
+
+ TISInputSourceRef new_layout = TISCopyCurrentKeyboardLayoutInputSource ();
+ CFDataRef layout_data_ref;
+
+ g_free (keyval_array);
+ keyval_array = g_new0 (guint, NUM_KEYCODES * KEYVALS_PER_KEYCODE);
+
+ layout_data_ref = (CFDataRef)TISGetInputSourceProperty (new_layout, kTISPropertyUnicodeKeyLayoutData);
+
+ if (layout_data_ref)
+ chr_data = CFDataGetBytePtr (layout_data_ref);
+
+ if (chr_data == NULL)
+ {
+ g_error ("cannot get keyboard layout data");
+ return;
+ }
+
+ for (i = 0; i < NUM_KEYCODES; i++)
+ {
+ int j;
+ UInt32 modifiers[] = {0, shiftKey, optionKey, shiftKey | optionKey};
+ UniChar chars[4];
+ UniCharCount nChars;
+
+ p = keyval_array + i * KEYVALS_PER_KEYCODE;
+
+ for (j = 0; j < KEYVALS_PER_KEYCODE; j++)
+ {
+ UInt32 state = 0;
+ OSStatus err;
+ UInt16 key_code;
+ UniChar uc;
+
+ key_code = modifiers[j] | i;
+ err = UCKeyTranslate (chr_data, i, kUCKeyActionDisplay,
+ (modifiers[j] >> 8) & 0xFF,
+ LMGetKbdType(),
+ 0,
+ &state, 4, &nChars, chars);
+
+ /* FIXME: Theoretically, we can get multiple UTF-16
+ * values; we should convert them to proper unicode and
+ * figure out whether there are really keyboard layouts
+ * that give us more than one character for one
+ * keypress.
+ */
+ if (err == noErr && nChars == 1)
+ {
+ int k;
+ gboolean found = FALSE;
+
+ /* A few <Shift><Option>keys return two characters,
+ * the first of which is U+00a0, which isn't
+ * interesting; so we return the second. More
+ * sophisticated handling is the job of a
+ * GtkIMContext.
+ *
+ * If state isn't zero, it means that it's a dead
+ * key of some sort. Some of those are enumerated in
+ * the special_ucs_table with the high nibble set to
+ * f to push it into the private use range. Here we
+ * do the same.
+ */
+ if (state != 0)
+ chars[nChars - 1] |= 0xf000;
+ uc = chars[nChars - 1];
+
+ for (k = 0; k < G_N_ELEMENTS (special_ucs_table); k++)
+ {
+ if (special_ucs_table[k].ucs_value == uc)
+ {
+ p[j] = special_ucs_table[k].keyval;
+ found = TRUE;
+ break;
+ }
+ }
+
+ /* Special-case shift-tab since GTK+ expects
+ * GDK_KEY_ISO_Left_Tab for that.
+ */
+ if (found && p[j] == GDK_KEY_Tab && modifiers[j] == shiftKey)
+ p[j] = GDK_KEY_ISO_Left_Tab;
+
+ if (!found)
+ p[j] = gdk_unicode_to_keyval (uc);
+ }
+ }
+
+ if (p[3] == p[2])
+ p[3] = 0;
+ if (p[2] == p[1])
+ p[2] = 0;
+ if (p[1] == p[0])
+ p[1] = 0;
+ if (p[0] == p[2] &&
+ p[1] == p[3])
+ p[2] = p[3] = 0;
+ }
+
+ for (i = 0; i < G_N_ELEMENTS (modifier_keys); i++)
+ {
+ p = keyval_array + modifier_keys[i].keycode * KEYVALS_PER_KEYCODE;
+
+ if (p[0] == 0 && p[1] == 0 &&
+ p[2] == 0 && p[3] == 0)
+ p[0] = modifier_keys[i].keyval;
+ }
+
+ for (i = 0; i < G_N_ELEMENTS (function_keys); i++)
+ {
+ p = keyval_array + function_keys[i].keycode * KEYVALS_PER_KEYCODE;
+
+ p[0] = function_keys[i].keyval;
+ p[1] = p[2] = p[3] = 0;
+ }
+
+ for (i = 0; i < G_N_ELEMENTS (known_numeric_keys); i++)
+ {
+ p = keyval_array + known_numeric_keys[i].keycode * KEYVALS_PER_KEYCODE;
+
+ if (p[0] == known_numeric_keys[i].normal_keyval)
+ p[0] = known_numeric_keys[i].keypad_keyval;
+ }
+
+ g_signal_emit_by_name (self, "keys-changed");
+}
+
+static PangoDirection
+gdk_macos_keymap_get_direction (GdkKeymap *keymap)
+{
+ return PANGO_DIRECTION_NEUTRAL;
+}
+
+static gboolean
+gdk_macos_keymap_have_bidi_layouts (GdkKeymap *keymap)
+{
+ return FALSE;
+}
+
+static gboolean
+gdk_macos_keymap_get_caps_lock_state (GdkKeymap *keymap)
+{
+ return FALSE;
+}
+
+static gboolean
+gdk_macos_keymap_get_num_lock_state (GdkKeymap *keymap)
+{
+ return FALSE;
+}
+
+static gboolean
+gdk_macos_keymap_get_scroll_lock_state (GdkKeymap *keymap)
+{
+ return FALSE;
+}
+
+static guint
+gdk_macos_keymap_lookup_key (GdkKeymap *keymap,
+ const GdkKeymapKey *key)
+{
+ GdkMacosKeymap *self = (GdkMacosKeymap *)keymap;
+
+ g_assert (GDK_IS_MACOS_KEYMAP (self));
+ g_assert (key != NULL);
+
+ return GET_KEYVAL (key->keycode, key->group, key->level);
+}
+
+static guint
+translate_keysym (guint hardware_keycode,
+ gint group,
+ GdkModifierType state,
+ gint *effective_group,
+ gint *effective_level)
+{
+ gint level;
+ guint tmp_keyval;
+
+ level = (state & GDK_SHIFT_MASK) ? 1 : 0;
+
+ if (!(GET_KEYVAL (hardware_keycode, group, 0) || GET_KEYVAL (hardware_keycode, group, 1)) &&
+ (GET_KEYVAL (hardware_keycode, 0, 0) || GET_KEYVAL (hardware_keycode, 0, 1)))
+ group = 0;
+
+ if (!GET_KEYVAL (hardware_keycode, group, level) &&
+ GET_KEYVAL (hardware_keycode, group, 0))
+ level = 0;
+
+ tmp_keyval = GET_KEYVAL (hardware_keycode, group, level);
+
+ if (state & GDK_LOCK_MASK)
+ {
+ guint upper = gdk_keyval_to_upper (tmp_keyval);
+ if (upper != tmp_keyval)
+ tmp_keyval = upper;
+ }
+
+ if (effective_group)
+ *effective_group = group;
+ if (effective_level)
+ *effective_level = level;
+
+ return tmp_keyval;
+}
+
+static gboolean
+gdk_macos_keymap_get_entries_for_keyval (GdkKeymap *keymap,
+ guint keyval,
+ GArray *keys)
+{
+ gboolean ret = FALSE;
+
+ g_assert (GDK_IS_MACOS_KEYMAP (keymap));
+ g_assert (keys != NULL);
+
+ for (guint i = 0; i < NUM_KEYCODES * KEYVALS_PER_KEYCODE; i++)
+ {
+ GdkKeymapKey key;
+
+ if (keyval_array[i] != keyval)
+ continue;
+
+ key.keycode = i / KEYVALS_PER_KEYCODE;
+ key.group = (i % KEYVALS_PER_KEYCODE) >= 2;
+ key.level = i % 2;
+
+ g_array_append_val (keys, key);
+
+ ret = TRUE;
+ }
+
+ return ret;
+}
+
+static gboolean
+gdk_macos_keymap_get_entries_for_keycode (GdkKeymap *keymap,
+ guint hardware_keycode,
+ GdkKeymapKey **keys,
+ guint **keyvals,
+ gint *n_entries)
+{
+ GArray *keys_array;
+ GArray *keyvals_array;
+ guint *p;
+ guint i;
+
+ g_assert (GDK_IS_MACOS_KEYMAP (keymap));
+ g_assert (keyvals != NULL);
+ g_assert (n_entries != NULL);
+
+ *keyvals = NULL;
+ *n_entries = 0;
+
+ if (hardware_keycode > NUM_KEYCODES)
+ return FALSE;
+
+ if (keys)
+ keys_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
+ else
+ keys_array = NULL;
+
+ if (keyvals)
+ keyvals_array = g_array_new (FALSE, FALSE, sizeof (guint));
+ else
+ keyvals_array = NULL;
+
+ p = keyval_array + hardware_keycode * KEYVALS_PER_KEYCODE;
+
+ for (i = 0; i < KEYVALS_PER_KEYCODE; i++)
+ {
+ if (!p[i])
+ continue;
+
+ (*n_entries)++;
+
+ if (keyvals_array)
+ g_array_append_val (keyvals_array, p[i]);
+
+ if (keys_array)
+ {
+ GdkKeymapKey key;
+
+ key.keycode = hardware_keycode;
+ key.group = i >= 2;
+ key.level = i % 2;
+
+ g_array_append_val (keys_array, key);
+ }
+ }
+
+ if (keys)
+ *keys = (GdkKeymapKey *)(gpointer)g_array_free (keys_array, FALSE);
+
+ if (keyvals)
+ *keyvals = (guint *)(gpointer)g_array_free (keyvals_array, FALSE);
+
+ return *n_entries > 0;
+}
+
+static gboolean
+gdk_macos_keymap_translate_keyboard_state (GdkKeymap *keymap,
+ guint hardware_keycode,
+ GdkModifierType state,
+ gint group,
+ guint *keyval,
+ gint *effective_group,
+ gint *level,
+ GdkModifierType *consumed_modifiers)
+{
+ guint tmp_keyval;
+ GdkModifierType bit;
+
+ g_assert (GDK_IS_MACOS_KEYMAP (keymap));
+
+ if (keyval)
+ *keyval = 0;
+ if (effective_group)
+ *effective_group = 0;
+ if (level)
+ *level = 0;
+ if (consumed_modifiers)
+ *consumed_modifiers = 0;
+
+ if (hardware_keycode < 0 || hardware_keycode >= NUM_KEYCODES)
+ return FALSE;
+
+ tmp_keyval = translate_keysym (hardware_keycode, group, state, level, effective_group);
+
+ /* Check if modifiers modify the keyval */
+ if (consumed_modifiers)
+ {
+ guint tmp_modifiers = (state & GDK_MODIFIER_MASK);
+
+ for (bit = 1; bit <= tmp_modifiers; bit <<= 1)
+ {
+ if ((bit & tmp_modifiers) &&
+ translate_keysym (hardware_keycode, group, state & ~bit,
+ NULL, NULL) == tmp_keyval)
+ tmp_modifiers &= ~bit;
+ }
+
+ *consumed_modifiers = tmp_modifiers;
+ }
+
+ if (keyval)
+ *keyval = tmp_keyval;
+
+ return TRUE;
+}
+
+static void
+input_sources_changed_notification (CFNotificationCenterRef center,
+ void *observer,
+ CFStringRef name,
+ const void *object,
+ CFDictionaryRef userInfo)
+{
+ GdkMacosKeymap *self = observer;
+
+ g_assert (GDK_IS_MACOS_KEYMAP (self));
+
+ gdk_macos_keymap_update (self);
+}
+
+static void
+gdk_macos_keymap_finalize (GObject *object)
+{
+ CFNotificationCenterRemoveObserver (CFNotificationCenterGetDistributedCenter (),
+ object,
+ CFSTR ("AppleSelectedInputSourcesChangedNotification"),
+ NULL);
+
+ G_OBJECT_CLASS (gdk_macos_keymap_parent_class)->finalize (object);
+}
+
+static void
+gdk_macos_keymap_class_init (GdkMacosKeymapClass *klass)
+{
+ GdkKeymapClass *keymap_class = GDK_KEYMAP_CLASS (klass);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gdk_macos_keymap_finalize;
+
+ keymap_class->get_caps_lock_state = gdk_macos_keymap_get_caps_lock_state;
+ keymap_class->get_direction = gdk_macos_keymap_get_direction;
+ keymap_class->get_entries_for_keycode = gdk_macos_keymap_get_entries_for_keycode;
+ keymap_class->get_entries_for_keyval = gdk_macos_keymap_get_entries_for_keyval;
+ keymap_class->get_num_lock_state = gdk_macos_keymap_get_num_lock_state;
+ keymap_class->get_scroll_lock_state = gdk_macos_keymap_get_scroll_lock_state;
+ keymap_class->have_bidi_layouts = gdk_macos_keymap_have_bidi_layouts;
+ keymap_class->lookup_key = gdk_macos_keymap_lookup_key;
+ keymap_class->translate_keyboard_state = gdk_macos_keymap_translate_keyboard_state;
+}
+
+static void
+gdk_macos_keymap_init (GdkMacosKeymap *self)
+{
+ CFNotificationCenterAddObserver (CFNotificationCenterGetDistributedCenter (),
+ self,
+ input_sources_changed_notification,
+ CFSTR ("AppleSelectedInputSourcesChangedNotification"),
+ NULL,
+ CFNotificationSuspensionBehaviorDeliverImmediately);
+ gdk_macos_keymap_update (self);
+}
+
+GdkMacosKeymap *
+_gdk_macos_keymap_new (GdkMacosDisplay *display)
+{
+ g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (display), NULL);
+
+ return g_object_new (GDK_TYPE_MACOS_KEYMAP,
+ "display", display,
+ NULL);
+}
+
+/* What sort of key event is this? Returns one of
+ * GDK_KEY_PRESS, GDK_KEY_RELEASE, GDK_NOTHING (should be ignored)
+ */
+GdkEventType
+_gdk_macos_keymap_get_event_type (NSEvent *event)
+{
+ unsigned short keycode;
+ unsigned int flags;
+
+ switch ((int)[event type])
+ {
+ case NSEventTypeKeyDown:
+ return GDK_KEY_PRESS;
+ case NSEventTypeKeyUp:
+ return GDK_KEY_RELEASE;
+ case NSEventTypeFlagsChanged:
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ /* For flags-changed events, we have to find the special key that caused the
+ * event, and see if it's in the modifier mask. */
+ keycode = [event keyCode];
+ flags = [event modifierFlags];
+
+ for (guint i = 0; i < G_N_ELEMENTS (modifier_keys); i++)
+ {
+ if (modifier_keys[i].keycode == keycode)
+ {
+ if (flags & modifier_keys[i].modmask)
+ return GDK_KEY_PRESS;
+ else
+ return GDK_KEY_RELEASE;
+ }
+ }
+
+ /* Some keypresses (eg: Expose' activations) seem to trigger flags-changed
+ * events for no good reason. Ignore them! */
+ return 0;
+}
+
+gboolean
+_gdk_macos_keymap_is_modifier (guint keycode)
+{
+ for (guint i = 0; i < G_N_ELEMENTS (modifier_keys); i++)
+ {
+ if (modifier_keys[i].modmask == 0)
+ break;
+
+ if (modifier_keys[i].keycode == keycode)
+ return TRUE;
+ }
+
+ return FALSE;
+}
--- /dev/null
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef __GDK_MACOS_KEYMAP_H__
+#define __GDK_MACOS_KEYMAP_H__
+
+#if !defined (__GDKMACOS_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gdk/macos/gdkmacos.h> can be included directly."
+#endif
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GdkMacosKeymap GdkMacosKeymap;
+typedef struct _GdkMacosKeymapClass GdkMacosKeymapClass;
+
+#define GDK_TYPE_MACOS_KEYMAP (gdk_macos_keymap_get_type())
+#define GDK_MACOS_KEYMAP(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_MACOS_KEYMAP, GdkMacosKeymap))
+#define GDK_IS_MACOS_KEYMAP(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MACOS_KEYMAP))
+
+GDK_AVAILABLE_IN_ALL
+GType gdk_macos_keymap_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GDK_MACOS_KEYMAP_H__ */
--- /dev/null
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef __GDK_MACOS_MONITOR_PRIVATE_H__
+#define __GDK_MACOS_MONITOR_PRIVATE_H__
+
+#include <AppKit/AppKit.h>
+
+#include "gdkmacosdisplay.h"
+#include "gdkmacosmonitor.h"
+
+#include "gdkmonitorprivate.h"
+
+G_BEGIN_DECLS
+
+GdkMacosMonitor *_gdk_macos_monitor_new (GdkMacosDisplay *display,
+ CGDirectDisplayID screen_id);
+CGDirectDisplayID _gdk_macos_monitor_get_screen_id (GdkMacosMonitor *self);
+gboolean _gdk_macos_monitor_reconfigure (GdkMacosMonitor *self);
+
+G_END_DECLS
+
+#endif /* __GDK_MACOS_MONITOR_PRIVATE_H__ */
--- /dev/null
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#include <gdk/gdk.h>
+#include <math.h>
+
+#include "gdkmacosdisplay-private.h"
+#include "gdkmacosmonitor-private.h"
+#include "gdkmacosutils-private.h"
+
+struct _GdkMacosMonitor
+{
+ GdkMonitor parent_instance;
+ CGDirectDisplayID screen_id;
+ NSRect workarea;
+ guint has_opengl : 1;
+};
+
+struct _GdkMacosMonitorClass
+{
+ GdkMonitorClass parent_class;
+};
+
+G_DEFINE_TYPE (GdkMacosMonitor, gdk_macos_monitor, GDK_TYPE_MONITOR)
+
+static void
+gdk_macos_monitor_get_workarea (GdkMonitor *monitor,
+ GdkRectangle *geometry)
+{
+ GDK_BEGIN_MACOS_ALLOC_POOL;
+
+ GdkMacosMonitor *self = (GdkMacosMonitor *)monitor;
+ int x, y;
+
+ g_assert (GDK_IS_MACOS_MONITOR (self));
+ g_assert (geometry != NULL);
+
+ x = self->workarea.origin.x;
+ y = self->workarea.origin.y + self->workarea.size.height;
+
+ _gdk_macos_display_from_display_coords (GDK_MACOS_DISPLAY (monitor->display),
+ x, y,
+ &x, &y);
+
+ geometry->x = x;
+ geometry->y = y;
+ geometry->width = self->workarea.size.width;
+ geometry->height = self->workarea.size.height;
+
+ GDK_END_MACOS_ALLOC_POOL;
+}
+
+static void
+gdk_macos_monitor_class_init (GdkMacosMonitorClass *klass)
+{
+ GdkMonitorClass *monitor_class = GDK_MONITOR_CLASS (klass);
+
+ monitor_class->get_workarea = gdk_macos_monitor_get_workarea;
+}
+
+static void
+gdk_macos_monitor_init (GdkMacosMonitor *self)
+{
+}
+
+static GdkSubpixelLayout
+GetSubpixelLayout (CGDirectDisplayID screen_id)
+{
+#if 0
+ GDK_BEGIN_MACOS_ALLOC_POOL;
+
+ GdkSubpixelLayout subpixel_layout = GDK_SUBPIXEL_LAYOUT_UNKNOWN;
+ io_service_t iosvc;
+ NSDictionary *dict;
+ guint layout;
+ gboolean rotation;
+
+ rotation = CGDisplayRotation (screen_id);
+ iosvc = CGDisplayIOServicePort (screen_id);
+ dict = (NSDictionary *)IODisplayCreateInfoDictionary (iosvc, kIODisplayOnlyPreferredName);
+ layout = [[dict objectForKey:@kDisplaySubPixelLayout] unsignedIntValue];
+
+ switch (layout)
+ {
+ case kDisplaySubPixelLayoutRGB:
+ if (rotation == 0.0)
+ subpixel_layout = GDK_SUBPIXEL_LAYOUT_HORIZONTAL_RGB;
+ else if (rotation == 90.0)
+ subpixel_layout = GDK_SUBPIXEL_LAYOUT_VERTICAL_RGB;
+ else if (rotation == 180.0 || rotation == -180.0)
+ subpixel_layout = GDK_SUBPIXEL_LAYOUT_HORIZONTAL_BGR;
+ else if (rotation == -90.0)
+ subpixel_layout = GDK_SUBPIXEL_LAYOUT_VERTICAL_BGR;
+ break;
+
+ case kDisplaySubPixelLayoutBGR:
+ if (rotation == 0.0)
+ subpixel_layout = GDK_SUBPIXEL_LAYOUT_HORIZONTAL_BGR;
+ else if (rotation == 90.0)
+ subpixel_layout = GDK_SUBPIXEL_LAYOUT_VERTICAL_BGR;
+ else if (rotation == 180.0 || rotation == -180.0)
+ subpixel_layout = GDK_SUBPIXEL_LAYOUT_HORIZONTAL_RGB;
+ else if (rotation == -90.0 || rotation == 270.0)
+ subpixel_layout = GDK_SUBPIXEL_LAYOUT_VERTICAL_RGB;
+ break;
+
+ default:
+ break;
+ }
+
+ GDK_END_MACOS_ALLOC_POOL;
+
+ return subpixel_layout;
+#endif
+
+ return GDK_SUBPIXEL_LAYOUT_UNKNOWN;
+}
+
+static char *
+GetLocalizedName (NSScreen *screen)
+{
+ GDK_BEGIN_MACOS_ALLOC_POOL;
+
+ NSString *str;
+ char *name;
+
+ g_assert (screen);
+
+ str = [screen localizedName];
+ name = g_strdup ([str UTF8String]);
+
+ GDK_END_MACOS_ALLOC_POOL;
+
+ return g_steal_pointer (&name);
+}
+
+static gchar *
+GetConnectorName (CGDirectDisplayID screen_id)
+{
+ guint unit = CGDisplayUnitNumber (screen_id);
+ return g_strdup_printf ("unit-%u", unit);
+}
+
+static NSScreen *
+find_screen (CGDirectDisplayID screen_id)
+{
+ GDK_BEGIN_MACOS_ALLOC_POOL;
+
+ NSScreen *screen = NULL;
+
+ for (id obj in [NSScreen screens])
+ {
+ if (screen_id == [[[obj deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue])
+ {
+ screen = (NSScreen *)obj;
+ break;
+ }
+ }
+
+ GDK_END_MACOS_ALLOC_POOL;
+
+ return screen;
+}
+
+gboolean
+_gdk_macos_monitor_reconfigure (GdkMacosMonitor *self)
+{
+ GdkSubpixelLayout subpixel_layout;
+ CGDisplayModeRef mode;
+ GdkMacosDisplay *display;
+ NSScreen *screen;
+ GdkRectangle geom;
+ gboolean has_opengl;
+ CGSize size;
+ CGRect bounds;
+ size_t width;
+ size_t pixel_width;
+ gchar *connector;
+ gchar *name;
+ int refresh_rate;
+ int scale_factor = 1;
+ int width_mm;
+ int height_mm;
+
+ g_return_val_if_fail (GDK_IS_MACOS_MONITOR (self), FALSE);
+
+ display = GDK_MACOS_DISPLAY (GDK_MONITOR (self)->display);
+
+ if (!(screen = find_screen (self->screen_id)) ||
+ !(mode = CGDisplayCopyDisplayMode (self->screen_id)))
+ return FALSE;
+
+ size = CGDisplayScreenSize (self->screen_id);
+ bounds = [screen frame];
+ width = CGDisplayModeGetWidth (mode);
+ pixel_width = CGDisplayModeGetPixelWidth (mode);
+ has_opengl = CGDisplayUsesOpenGLAcceleration (self->screen_id);
+ subpixel_layout = GetSubpixelLayout (self->screen_id);
+ name = GetLocalizedName (screen);
+ connector = GetConnectorName (self->screen_id);
+
+ if (width != 0 && pixel_width != 0)
+ scale_factor = MAX (1, pixel_width / width);
+
+ width_mm = size.width;
+ height_mm = size.height;
+
+ geom.x = bounds.origin.x - display->min_x;
+ geom.y = display->height - bounds.origin.y - bounds.size.height + display->min_y;
+ geom.width = bounds.size.width;
+ geom.height = bounds.size.height;
+
+ /* We will often get 0 back from CGDisplayModeGetRefreshRate(). We
+ * can fallback by getting it from CoreVideo based on a CVDisplayLink
+ * setting (which is also used by the frame clock).
+ */
+ if (!(refresh_rate = CGDisplayModeGetRefreshRate (mode)))
+ refresh_rate = _gdk_macos_display_get_nominal_refresh_rate (display);
+
+ gdk_monitor_set_connector (GDK_MONITOR (self), connector);
+ gdk_monitor_set_model (GDK_MONITOR (self), name);
+ gdk_monitor_set_geometry (GDK_MONITOR (self), &geom);
+ gdk_monitor_set_physical_size (GDK_MONITOR (self), width_mm, height_mm);
+ gdk_monitor_set_scale_factor (GDK_MONITOR (self), scale_factor);
+ gdk_monitor_set_refresh_rate (GDK_MONITOR (self), refresh_rate);
+ gdk_monitor_set_subpixel_layout (GDK_MONITOR (self), GDK_SUBPIXEL_LAYOUT_UNKNOWN);
+
+ self->workarea = [screen visibleFrame];
+
+ /* We might be able to use this at some point to change which GSK renderer
+ * we use for surfaces on this monitor. For example, it might be better
+ * to use cairo if we cannot use OpenGL (or it would be software) anyway.
+ * Presumably that is more common in cases where macOS is running under
+ * an emulator such as QEMU.
+ */
+ self->has_opengl = !!has_opengl;
+
+ CGDisplayModeRelease (mode);
+ g_free (name);
+ g_free (connector);
+
+ return TRUE;
+}
+
+GdkMacosMonitor *
+_gdk_macos_monitor_new (GdkMacosDisplay *display,
+ CGDirectDisplayID screen_id)
+{
+ GdkMacosMonitor *self;
+
+ g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (display), NULL);
+
+ self = g_object_new (GDK_TYPE_MACOS_MONITOR,
+ "display", display,
+ NULL);
+
+ self->screen_id = screen_id;
+
+ _gdk_macos_monitor_reconfigure (self);
+
+ return g_steal_pointer (&self);
+}
+
+CGDirectDisplayID
+_gdk_macos_monitor_get_screen_id (GdkMacosMonitor *self)
+{
+ g_return_val_if_fail (GDK_IS_MACOS_MONITOR (self), 0);
+
+ return self->screen_id;
+}
--- /dev/null
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef __GDK_MACOS_MONITOR_H__
+#define __GDK_MACOS_MONITOR_H__
+
+#if !defined (__GDKMACOS_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gdk/macos/gdkmacos.h> can be included directly."
+#endif
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GdkMacosMonitor GdkMacosMonitor;
+typedef struct _GdkMacosMonitorClass GdkMacosMonitorClass;
+
+#define GDK_TYPE_MACOS_MONITOR (gdk_macos_monitor_get_type())
+#define GDK_MACOS_MONITOR(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_MACOS_MONITOR, GdkMacosMonitor))
+#define GDK_IS_MACOS_MONITOR(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MACOS_MONITOR))
+
+GDK_AVAILABLE_IN_ALL
+GType gdk_macos_monitor_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GDK_MACOS_MONITOR_H__ */
--- /dev/null
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef __GDK_MACOS_POPUP_SURFACE_PRIVATE_H__
+#define __GDK_MACOS_POPUP_SURFACE_PRIVATE_H__
+
+#include "gdkmacossurface-private.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GdkMacosPopupSurface GdkMacosPopupSurface;
+typedef struct _GdkMacosPopupSurfaceClass GdkMacosPopupSurfaceClass;
+
+#define GDK_TYPE_MACOS_POPUP_SURFACE (_gdk_macos_popup_surface_get_type())
+#define GDK_MACOS_POPUP_SURFACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_MACOS_POPUP_SURFACE, GdkMacosPopupSurface))
+#define GDK_IS_MACOS_POPUP_SURFACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MACOS_POPUP_SURFACE))
+
+GType _gdk_macos_popup_surface_get_type (void);
+GdkMacosSurface *_gdk_macos_popup_surface_new (GdkMacosDisplay *display,
+ GdkSurface *parent,
+ GdkFrameClock *frame_clock,
+ int x,
+ int y,
+ int width,
+ int height);
+void _gdk_macos_popup_surface_attach_to_parent (GdkMacosPopupSurface *self);
+void _gdk_macos_popup_surface_detach_from_parent (GdkMacosPopupSurface *self);
+void _gdk_macos_popup_surface_reposition (GdkMacosPopupSurface *self);
+
+G_END_DECLS
+
+#endif /* __GDK_MACOS_POPUP_SURFACE_PRIVATE_H__ */
--- /dev/null
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#import "GdkMacosWindow.h"
+
+#include "gdkinternals.h"
+#include "gdkpopupprivate.h"
+
+#include "gdkmacosdisplay-private.h"
+#include "gdkmacospopupsurface-private.h"
+#include "gdkmacosutils-private.h"
+
+struct _GdkMacosPopupSurface
+{
+ GdkMacosSurface parent_instance;
+ GdkPopupLayout *layout;
+};
+
+struct _GdkMacosPopupSurfaceClass
+{
+ GdkMacosSurfaceClass parent_class;
+};
+
+static void
+gdk_macos_popup_surface_layout (GdkMacosPopupSurface *self,
+ int width,
+ int height,
+ GdkPopupLayout *layout)
+{
+ GdkRectangle final_rect;
+ int x, y;
+
+ g_assert (GDK_IS_MACOS_POPUP_SURFACE (self));
+ g_assert (layout != NULL);
+ g_assert (GDK_SURFACE (self)->parent);
+
+ if (layout != self->layout)
+ {
+ g_clear_pointer (&self->layout, gdk_popup_layout_unref);
+ self->layout = gdk_popup_layout_ref (layout);
+ }
+
+ gdk_surface_layout_popup_helper (GDK_SURFACE (self),
+ width,
+ height,
+ layout,
+ &final_rect);
+
+ gdk_surface_get_origin (GDK_SURFACE (self)->parent, &x, &y);
+
+ x += final_rect.x;
+ y += final_rect.y;
+
+ if (final_rect.width != GDK_SURFACE (self)->width ||
+ final_rect.height != GDK_SURFACE (self)->height)
+ _gdk_macos_surface_move_resize (GDK_MACOS_SURFACE (self),
+ x,
+ y,
+ final_rect.width,
+ final_rect.height);
+ else if (x != GDK_MACOS_SURFACE (self)->root_x ||
+ y != GDK_MACOS_SURFACE (self)->root_y)
+ _gdk_macos_surface_move (GDK_MACOS_SURFACE (self), x, y);
+ else
+ return;
+
+ gdk_surface_invalidate_rect (GDK_SURFACE (self), NULL);
+}
+
+static void
+show_popup (GdkMacosPopupSurface *self)
+{
+ _gdk_macos_surface_show (GDK_MACOS_SURFACE (self));
+}
+
+static void
+show_grabbing_popup (GdkSeat *seat,
+ GdkSurface *surface,
+ gpointer user_data)
+{
+ show_popup (GDK_MACOS_POPUP_SURFACE (surface));
+}
+
+static gboolean
+gdk_macos_popup_surface_present (GdkPopup *popup,
+ int width,
+ int height,
+ GdkPopupLayout *layout)
+{
+ GdkMacosPopupSurface *self = (GdkMacosPopupSurface *)popup;
+
+ g_assert (GDK_IS_MACOS_POPUP_SURFACE (self));
+
+ gdk_macos_popup_surface_layout (self, width, height, layout);
+
+ GDK_MACOS_SURFACE (self)->did_initial_present = TRUE;
+
+ if (GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self)))
+ return TRUE;
+
+ if (GDK_SURFACE (self)->autohide)
+ {
+ GdkDisplay *display = gdk_surface_get_display (GDK_SURFACE (popup));
+ GdkSeat *seat = gdk_display_get_default_seat (display);
+
+ gdk_seat_grab (seat,
+ GDK_SURFACE (self),
+ GDK_SEAT_CAPABILITY_ALL,
+ TRUE,
+ NULL, NULL,
+ show_grabbing_popup,
+ NULL);
+ }
+ else
+ {
+ show_popup (GDK_MACOS_POPUP_SURFACE (self));
+ }
+
+ return GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self));
+}
+
+static GdkGravity
+gdk_macos_popup_surface_get_surface_anchor (GdkPopup *popup)
+{
+ return GDK_SURFACE (popup)->popup.surface_anchor;
+}
+
+static GdkGravity
+gdk_macos_popup_surface_get_rect_anchor (GdkPopup *popup)
+{
+ return GDK_SURFACE (popup)->popup.rect_anchor;
+}
+
+static int
+gdk_macos_popup_surface_get_position_x (GdkPopup *popup)
+{
+ return GDK_SURFACE (popup)->x;
+}
+
+static int
+gdk_macos_popup_surface_get_position_y (GdkPopup *popup)
+{
+ return GDK_SURFACE (popup)->y;
+}
+
+static void
+popup_interface_init (GdkPopupInterface *iface)
+{
+ iface->present = gdk_macos_popup_surface_present;
+ iface->get_surface_anchor = gdk_macos_popup_surface_get_surface_anchor;
+ iface->get_rect_anchor = gdk_macos_popup_surface_get_rect_anchor;
+ iface->get_position_x = gdk_macos_popup_surface_get_position_x;
+ iface->get_position_y = gdk_macos_popup_surface_get_position_y;
+}
+
+G_DEFINE_TYPE_WITH_CODE (GdkMacosPopupSurface, _gdk_macos_popup_surface, GDK_TYPE_MACOS_SURFACE,
+ G_IMPLEMENT_INTERFACE (GDK_TYPE_POPUP, popup_interface_init))
+
+enum {
+ PROP_0,
+ LAST_PROP,
+};
+
+static void
+_gdk_macos_popup_surface_finalize (GObject *object)
+{
+ GdkMacosPopupSurface *self = (GdkMacosPopupSurface *)object;
+
+ g_clear_object (&GDK_SURFACE (self)->parent);
+ g_clear_pointer (&self->layout, gdk_popup_layout_unref);
+
+ G_OBJECT_CLASS (_gdk_macos_popup_surface_parent_class)->finalize (object);
+}
+
+static void
+_gdk_macos_popup_surface_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdkSurface *surface = GDK_SURFACE (object);
+
+ switch (prop_id)
+ {
+ case LAST_PROP + GDK_POPUP_PROP_PARENT:
+ g_value_set_object (value, surface->parent);
+ break;
+
+ case LAST_PROP + GDK_POPUP_PROP_AUTOHIDE:
+ g_value_set_boolean (value, surface->autohide);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+_gdk_macos_popup_surface_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdkSurface *surface = GDK_SURFACE (object);
+
+ switch (prop_id)
+ {
+ case LAST_PROP + GDK_POPUP_PROP_PARENT:
+ surface->parent = g_value_dup_object (value);
+ if (surface->parent)
+ surface->parent->children = g_list_prepend (surface->parent->children, surface);
+ break;
+
+ case LAST_PROP + GDK_POPUP_PROP_AUTOHIDE:
+ surface->autohide = g_value_get_boolean (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+_gdk_macos_popup_surface_class_init (GdkMacosPopupSurfaceClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = _gdk_macos_popup_surface_finalize;
+ object_class->get_property = _gdk_macos_popup_surface_get_property;
+ object_class->set_property = _gdk_macos_popup_surface_set_property;
+
+ gdk_popup_install_properties (object_class, 1);
+}
+
+static void
+_gdk_macos_popup_surface_init (GdkMacosPopupSurface *self)
+{
+}
+
+GdkMacosSurface *
+_gdk_macos_popup_surface_new (GdkMacosDisplay *display,
+ GdkSurface *parent,
+ GdkFrameClock *frame_clock,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ GDK_BEGIN_MACOS_ALLOC_POOL;
+
+ GdkMacosWindow *window;
+ GdkMacosSurface *self;
+ NSScreen *screen;
+ NSUInteger style_mask;
+ NSRect content_rect;
+ NSRect screen_rect;
+ int nx;
+ int ny;
+
+ g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (display), NULL);
+ g_return_val_if_fail (!frame_clock || GDK_IS_FRAME_CLOCK (frame_clock), NULL);
+ g_return_val_if_fail (!parent || GDK_IS_MACOS_SURFACE (parent), NULL);
+
+ style_mask = NSWindowStyleMaskBorderless;
+
+ _gdk_macos_display_to_display_coords (display, x, y, &nx, &ny);
+
+ screen = _gdk_macos_display_get_screen_at_display_coords (display, nx, ny);
+ screen_rect = [screen frame];
+ nx -= screen_rect.origin.x;
+ ny -= screen_rect.origin.y;
+ content_rect = NSMakeRect (nx, ny - height, width, height);
+
+ window = [[GdkMacosWindow alloc] initWithContentRect:content_rect
+ styleMask:style_mask
+ backing:NSBackingStoreBuffered
+ defer:NO
+ screen:screen];
+
+ [window setOpaque:NO];
+ [window setBackgroundColor:[NSColor clearColor]];
+ [window setDecorated:NO];
+
+#if 0
+ /* NOTE: We could set these to be popup level, but then
+ * [NSApp orderedWindows] would not give us the windows
+ * back with the stacking order applied.
+ */
+ [window setLevel:NSPopUpMenuWindowLevel];
+#endif
+
+ self = g_object_new (GDK_TYPE_MACOS_POPUP_SURFACE,
+ "display", display,
+ "frame-clock", frame_clock,
+ "native", window,
+ "parent", parent,
+ NULL);
+
+ GDK_END_MACOS_ALLOC_POOL;
+
+ return g_steal_pointer (&self);
+}
+
+void
+_gdk_macos_popup_surface_attach_to_parent (GdkMacosPopupSurface *self)
+{
+ GdkSurface *surface = (GdkSurface *)self;
+
+ g_return_if_fail (GDK_IS_MACOS_POPUP_SURFACE (self));
+
+ if (GDK_SURFACE_DESTROYED (surface))
+ return;
+
+ if (surface->parent != NULL && !GDK_SURFACE_DESTROYED (surface->parent))
+ {
+ NSWindow *parent = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (surface->parent));
+ NSWindow *window = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (self));
+
+ [parent addChildWindow:window ordered:NSWindowAbove];
+
+ _gdk_macos_display_clear_sorting (GDK_MACOS_DISPLAY (surface->display));
+ }
+}
+
+void
+_gdk_macos_popup_surface_detach_from_parent (GdkMacosPopupSurface *self)
+{
+ GdkSurface *surface = (GdkSurface *)self;
+
+ g_return_if_fail (GDK_IS_MACOS_POPUP_SURFACE (self));
+
+ if (GDK_SURFACE_DESTROYED (surface))
+ return;
+
+ if (surface->parent != NULL && !GDK_SURFACE_DESTROYED (surface->parent))
+ {
+ NSWindow *parent = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (surface->parent));
+ NSWindow *window = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (self));
+
+ [parent removeChildWindow:window];
+
+ _gdk_macos_display_clear_sorting (GDK_MACOS_DISPLAY (surface->display));
+ }
+}
+
+void
+_gdk_macos_popup_surface_reposition (GdkMacosPopupSurface *self)
+{
+ g_return_if_fail (GDK_IS_MACOS_POPUP_SURFACE (self));
+
+ if (self->layout == NULL ||
+ !gdk_surface_get_mapped (GDK_SURFACE (self)) ||
+ GDK_SURFACE (self)->parent == NULL)
+ return;
+
+ gdk_macos_popup_surface_layout (self,
+ GDK_SURFACE (self)->width,
+ GDK_SURFACE (self)->height,
+ self->layout);
+}
--- /dev/null
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef __GDK_MACOS_SEAT_PRIVATE_H__
+#define __GDK_MACOS_SEAT_PRIVATE_H__
+
+#include <AppKit/AppKit.h>
+
+#include "gdkmacosdisplay.h"
+
+#include "gdkseatprivate.h"
+
+G_BEGIN_DECLS
+
+GdkSeat *_gdk_macos_seat_new (GdkMacosDisplay *display);
+
+G_END_DECLS
+
+#endif /* __GDK_MACOS_SEAT_PRIVATE_H__ */
--- /dev/null
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#include <gdk/gdk.h>
+
+#include "gdkdeviceprivate.h"
+#include "gdkseatdefaultprivate.h"
+
+#include "gdkmacosdevice.h"
+#include "gdkmacosseat-private.h"
+
+GdkSeat *
+_gdk_macos_seat_new (GdkMacosDisplay *display)
+{
+ GdkDevice *core_keyboard;
+ GdkDevice *core_pointer;
+ GdkSeat *seat;
+
+ g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (display), NULL);
+
+ core_pointer = g_object_new (GDK_TYPE_MACOS_DEVICE,
+ "name", "Core Pointer",
+ "type", GDK_DEVICE_TYPE_LOGICAL,
+ "source", GDK_SOURCE_MOUSE,
+ "has-cursor", TRUE,
+ "display", display,
+ NULL);
+ core_keyboard = g_object_new (GDK_TYPE_MACOS_DEVICE,
+ "name", "Core Keyboard",
+ "type", GDK_DEVICE_TYPE_LOGICAL,
+ "source", GDK_SOURCE_KEYBOARD,
+ "has-cursor", FALSE,
+ "display", display,
+ NULL);
+
+ _gdk_device_set_associated_device (GDK_DEVICE (core_pointer),
+ GDK_DEVICE (core_keyboard));
+ _gdk_device_set_associated_device (GDK_DEVICE (core_keyboard),
+ GDK_DEVICE (core_pointer));
+
+ seat = gdk_seat_default_new_for_logical_pair (core_pointer, core_keyboard);
+
+ g_object_unref (core_pointer);
+ g_object_unref (core_keyboard);
+
+ return g_steal_pointer (&seat);
+}
--- /dev/null
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef __GDK_MACOS_SURFACE_PRIVATE_H__
+#define __GDK_MACOS_SURFACE_PRIVATE_H__
+
+#include <AppKit/AppKit.h>
+#include <cairo.h>
+
+#include "gdkinternals.h"
+#include "gdksurfaceprivate.h"
+
+#include "gdkmacosdisplay.h"
+#include "gdkmacossurface.h"
+
+#import "GdkMacosWindow.h"
+
+G_BEGIN_DECLS
+
+#define GDK_MACOS_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_MACOS_SURFACE, GdkMacosSurfaceClass))
+#define GDK_IS_MACOS_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_MACOS_SURFACE))
+#define GDK_MACOS_SURFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_MACOS_SURFACE, GdkMacosSurfaceClass))
+
+struct _GdkMacosSurface
+{
+ GdkSurface parent_instance;
+
+ GList main;
+ GList sorted;
+ GList frame;
+
+ GdkMacosWindow *window;
+ GPtrArray *monitors;
+ cairo_region_t *input_region;
+ char *title;
+
+ int root_x;
+ int root_y;
+
+ int shadow_top;
+ int shadow_right;
+ int shadow_bottom;
+ int shadow_left;
+
+ gint64 pending_frame_counter;
+
+ guint did_initial_present : 1;
+};
+
+struct _GdkMacosSurfaceClass
+{
+ GdkSurfaceClass parent_class;
+};
+
+GdkMacosSurface *_gdk_macos_surface_new (GdkMacosDisplay *display,
+ GdkSurfaceType surface_type,
+ GdkSurface *parent,
+ int x,
+ int y,
+ int width,
+ int height);
+NSWindow *_gdk_macos_surface_get_native (GdkMacosSurface *self);
+CGDirectDisplayID _gdk_macos_surface_get_screen_id (GdkMacosSurface *self);
+const char *_gdk_macos_surface_get_title (GdkMacosSurface *self);
+void _gdk_macos_surface_set_title (GdkMacosSurface *self,
+ const gchar *title);
+void _gdk_macos_surface_get_shadow (GdkMacosSurface *self,
+ gint *top,
+ gint *right,
+ gint *bottom,
+ gint *left);
+NSView *_gdk_macos_surface_get_view (GdkMacosSurface *self);
+gboolean _gdk_macos_surface_get_modal_hint (GdkMacosSurface *self);
+void _gdk_macos_surface_set_modal_hint (GdkMacosSurface *self,
+ gboolean modal_hint);
+void _gdk_macos_surface_set_geometry_hints (GdkMacosSurface *self,
+ const GdkGeometry *geometry,
+ GdkSurfaceHints geom_mask);
+void _gdk_macos_surface_resize (GdkMacosSurface *self,
+ int width,
+ int height);
+void _gdk_macos_surface_update_fullscreen_state (GdkMacosSurface *self);
+void _gdk_macos_surface_update_position (GdkMacosSurface *self);
+void _gdk_macos_surface_show (GdkMacosSurface *self);
+void _gdk_macos_surface_thaw (GdkMacosSurface *self,
+ gint64 predicted_presentation_time,
+ gint64 refresh_interval);
+CGContextRef _gdk_macos_surface_acquire_context (GdkMacosSurface *self,
+ gboolean clear_scale,
+ gboolean antialias);
+void _gdk_macos_surface_release_context (GdkMacosSurface *self,
+ CGContextRef cg_context);
+void _gdk_macos_surface_synthesize_null_key (GdkMacosSurface *self);
+void _gdk_macos_surface_move (GdkMacosSurface *self,
+ int x,
+ int y);
+void _gdk_macos_surface_move_resize (GdkMacosSurface *self,
+ int x,
+ int y,
+ int width,
+ int height);
+gboolean _gdk_macos_surface_is_tracking (GdkMacosSurface *self,
+ NSTrackingArea *area);
+void _gdk_macos_surface_monitor_changed (GdkMacosSurface *self);
+GdkMonitor *_gdk_macos_surface_get_best_monitor (GdkMacosSurface *self);
+void _gdk_macos_surface_reposition_children (GdkMacosSurface *self);
+void _gdk_macos_surface_set_opacity (GdkMacosSurface *self,
+ double opacity);
+void _gdk_macos_surface_get_root_coords (GdkMacosSurface *self,
+ int *x,
+ int *y);
+
+G_END_DECLS
+
+#endif /* __GDK_MACOS_SURFACE_PRIVATE_H__ */
--- /dev/null
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#include <AppKit/AppKit.h>
+#include <float.h>
+#include <gdk/gdk.h>
+
+#import "GdkMacosCairoView.h"
+
+#include "gdkdeviceprivate.h"
+#include "gdkdisplay.h"
+#include "gdkframeclockidleprivate.h"
+#include "gdkinternals.h"
+#include "gdksurfaceprivate.h"
+
+#include "gdkmacosdevice.h"
+#include "gdkmacosdisplay-private.h"
+#include "gdkmacosdrag-private.h"
+#include "gdkmacosdragsurface-private.h"
+#include "gdkmacosglcontext-private.h"
+#include "gdkmacosmonitor-private.h"
+#include "gdkmacospopupsurface-private.h"
+#include "gdkmacossurface-private.h"
+#include "gdkmacostoplevelsurface-private.h"
+#include "gdkmacosutils-private.h"
+
+G_DEFINE_ABSTRACT_TYPE (GdkMacosSurface, gdk_macos_surface, GDK_TYPE_SURFACE)
+
+enum {
+ PROP_0,
+ PROP_NATIVE,
+ LAST_PROP
+};
+
+static GParamSpec *properties [LAST_PROP];
+
+static gboolean
+window_is_fullscreen (GdkMacosSurface *self)
+{
+ g_assert (GDK_IS_MACOS_SURFACE (self));
+
+ return ([self->window styleMask] & NSWindowStyleMaskFullScreen) != 0;
+}
+
+void
+_gdk_macos_surface_reposition_children (GdkMacosSurface *self)
+{
+ g_assert (GDK_IS_MACOS_SURFACE (self));
+
+ if (GDK_SURFACE_DESTROYED (self))
+ return;
+
+ if (!gdk_surface_get_mapped (GDK_SURFACE (self)))
+ return;
+
+ for (const GList *iter = GDK_SURFACE (self)->children;
+ iter != NULL;
+ iter = iter->next)
+ {
+ GdkMacosSurface *child = iter->data;
+
+ g_assert (GDK_IS_MACOS_SURFACE (child));
+
+ if (GDK_IS_MACOS_POPUP_SURFACE (child))
+ _gdk_macos_popup_surface_reposition (GDK_MACOS_POPUP_SURFACE (child));
+ }
+
+ if (GDK_IS_POPUP (self) || self->did_initial_present)
+ g_signal_emit_by_name (self, "popup-layout-changed");
+}
+
+static void
+gdk_macos_surface_set_input_region (GdkSurface *surface,
+ cairo_region_t *region)
+{
+}
+
+static void
+gdk_macos_surface_set_opaque_region (GdkSurface *surface,
+ cairo_region_t *region)
+{
+ NSView *nsview;
+
+ g_assert (GDK_IS_MACOS_SURFACE (surface));
+
+ if ((nsview = _gdk_macos_surface_get_view (GDK_MACOS_SURFACE (surface))) &&
+ GDK_IS_MACOS_CAIRO_VIEW (nsview))
+ [(GdkMacosCairoView *)nsview setOpaqueRegion:region];
+}
+
+static void
+gdk_macos_surface_hide (GdkSurface *surface)
+{
+ GdkMacosSurface *self = (GdkMacosSurface *)surface;
+ GdkSeat *seat;
+
+ g_assert (GDK_IS_MACOS_SURFACE (self));
+
+ seat = gdk_display_get_default_seat (surface->display);
+ gdk_seat_ungrab (seat);
+
+ [self->window hide];
+
+ _gdk_surface_clear_update_area (surface);
+}
+
+static gint
+gdk_macos_surface_get_scale_factor (GdkSurface *surface)
+{
+ GdkMacosSurface *self = (GdkMacosSurface *)surface;
+
+ g_assert (GDK_IS_MACOS_SURFACE (self));
+
+ return [self->window backingScaleFactor];
+}
+
+static void
+gdk_macos_surface_set_shadow_width (GdkSurface *surface,
+ int left,
+ int right,
+ int top,
+ int bottom)
+{
+ GdkMacosSurface *self = (GdkMacosSurface *)surface;
+
+ g_assert (GDK_IS_MACOS_SURFACE (self));
+
+ self->shadow_top = top;
+ self->shadow_right = right;
+ self->shadow_bottom = bottom;
+ self->shadow_left = left;
+
+ if (top || right || bottom || left)
+ [self->window setHasShadow:NO];
+}
+
+static void
+gdk_macos_surface_begin_frame (GdkMacosSurface *self)
+{
+ g_assert (GDK_IS_MACOS_SURFACE (self));
+
+}
+
+static void
+gdk_macos_surface_end_frame (GdkMacosSurface *self)
+{
+ GdkFrameTimings *timings;
+ GdkFrameClock *frame_clock;
+ GdkDisplay *display;
+
+ g_assert (GDK_IS_MACOS_SURFACE (self));
+
+ display = gdk_surface_get_display (GDK_SURFACE (self));
+ frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self));
+
+ if ((timings = gdk_frame_clock_get_current_timings (frame_clock)))
+ self->pending_frame_counter = timings->frame_counter;
+
+ _gdk_macos_display_add_frame_callback (GDK_MACOS_DISPLAY (display), self);
+
+ gdk_surface_freeze_updates (GDK_SURFACE (self));
+}
+
+static void
+gdk_macos_surface_before_paint (GdkMacosSurface *self,
+ GdkFrameClock *frame_clock)
+{
+ GdkSurface *surface = (GdkSurface *)self;
+
+ g_assert (GDK_IS_MACOS_SURFACE (self));
+ g_assert (GDK_IS_FRAME_CLOCK (frame_clock));
+
+ if (surface->update_freeze_count > 0)
+ return;
+
+ gdk_macos_surface_begin_frame (self);
+}
+
+static void
+gdk_macos_surface_after_paint (GdkMacosSurface *self,
+ GdkFrameClock *frame_clock)
+{
+ GdkSurface *surface = (GdkSurface *)self;
+
+ g_assert (GDK_IS_MACOS_SURFACE (self));
+ g_assert (GDK_IS_FRAME_CLOCK (frame_clock));
+
+ if (surface->update_freeze_count > 0)
+ return;
+
+ gdk_macos_surface_end_frame (self);
+}
+
+static void
+gdk_macos_surface_get_root_coords (GdkSurface *surface,
+ int x,
+ int y,
+ int *root_x,
+ int *root_y)
+{
+ GdkMacosSurface *self = (GdkMacosSurface *)surface;
+
+ g_assert (GDK_IS_MACOS_SURFACE (self));
+
+ if (root_x)
+ *root_x = self->root_x + x;
+
+ if (root_y)
+ *root_y = self->root_y + y;
+}
+
+static gboolean
+gdk_macos_surface_get_device_state (GdkSurface *surface,
+ GdkDevice *device,
+ gdouble *x,
+ gdouble *y,
+ GdkModifierType *mask)
+{
+ GdkDisplay *display;
+ NSWindow *nswindow;
+ NSPoint point;
+ int x_tmp;
+ int y_tmp;
+
+ g_assert (GDK_IS_MACOS_SURFACE (surface));
+ g_assert (GDK_IS_MACOS_DEVICE (device));
+ g_assert (x != NULL);
+ g_assert (y != NULL);
+ g_assert (mask != NULL);
+
+ display = gdk_surface_get_display (surface);
+ nswindow = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (surface));
+ point = [nswindow mouseLocationOutsideOfEventStream];
+
+ _gdk_macos_display_from_display_coords (GDK_MACOS_DISPLAY (display),
+ point.x, point.y,
+ &x_tmp, &y_tmp);
+
+ *x = x_tmp;
+ *y = x_tmp;
+
+ return TRUE;
+}
+
+static void
+gdk_macos_surface_get_geometry (GdkSurface *surface,
+ int *x,
+ int *y,
+ int *width,
+ int *height)
+{
+ g_assert (GDK_IS_MACOS_SURFACE (surface));
+
+ if (x != NULL)
+ *x = surface->x;
+
+ if (y != NULL)
+ *y = surface->y;
+
+ if (width != NULL)
+ *width = surface->width;
+
+ if (height != NULL)
+ *height = surface->height;
+}
+
+static GdkDrag *
+gdk_macos_surface_drag_begin (GdkSurface *surface,
+ GdkDevice *device,
+ GdkContentProvider *content,
+ GdkDragAction actions,
+ double dx,
+ double dy)
+{
+ GdkMacosSurface *self = (GdkMacosSurface *)surface;
+ GdkMacosSurface *drag_surface;
+ GdkMacosDrag *drag;
+ GdkCursor *cursor;
+ GdkSeat *seat;
+ double px;
+ double py;
+ int sx;
+ int sy;
+
+ g_assert (GDK_IS_MACOS_SURFACE (self));
+ g_assert (GDK_IS_MACOS_TOPLEVEL_SURFACE (self) ||
+ GDK_IS_MACOS_POPUP_SURFACE (self));
+ g_assert (GDK_IS_MACOS_DEVICE (device));
+ g_assert (GDK_IS_CONTENT_PROVIDER (content));
+
+ seat = gdk_device_get_seat (device);
+ _gdk_device_query_state (device, surface, NULL, &px, &py, NULL);
+ _gdk_macos_surface_get_root_coords (GDK_MACOS_SURFACE (surface), &sx, &sy);
+ drag_surface = _gdk_macos_surface_new (GDK_MACOS_DISPLAY (surface->display),
+ GDK_SURFACE_TEMP,
+ surface,
+ -99, -99, 1, 1);
+ drag = g_object_new (GDK_TYPE_MACOS_DRAG,
+ "drag-surface", drag_surface,
+ "surface", surface,
+ "device", device,
+ "content", content,
+ "actions", actions,
+ NULL);
+ g_clear_object (&drag_surface);
+
+ cursor = gdk_drag_get_cursor (GDK_DRAG (drag),
+ gdk_drag_get_selected_action (GDK_DRAG (drag)));
+ gdk_drag_set_cursor (GDK_DRAG (drag), cursor);
+
+ if (!_gdk_macos_drag_begin (drag))
+ {
+ g_object_unref (drag);
+ return NULL;
+ }
+
+ /* Hold a reference until drop_done is called */
+ g_object_ref (drag);
+
+ return GDK_DRAG (g_steal_pointer (&drag));
+}
+
+static GdkGLContext *
+gdk_macos_surface_create_gl_context (GdkSurface *surface,
+ gboolean attached,
+ GdkGLContext *share,
+ GError **error)
+{
+ GdkMacosSurface *self = (GdkMacosSurface *)surface;
+
+ g_assert (GDK_IS_MACOS_SURFACE (self));
+ g_assert (!share || GDK_IS_GL_CONTEXT (share));
+
+ return _gdk_macos_gl_context_new (self, attached, share, error);
+}
+
+static void
+gdk_macos_surface_destroy (GdkSurface *surface,
+ gboolean foreign_destroy)
+{
+ GDK_BEGIN_MACOS_ALLOC_POOL;
+
+ GdkMacosSurface *self = (GdkMacosSurface *)surface;
+ GdkMacosWindow *window = g_steal_pointer (&self->window);
+
+ g_clear_pointer (&self->title, g_free);
+
+ if (window != NULL)
+ [window close];
+
+ _gdk_macos_display_surface_removed (GDK_MACOS_DISPLAY (surface->display), self);
+
+ g_clear_pointer (&self->monitors, g_ptr_array_unref);
+
+ g_assert (self->sorted.prev == NULL);
+ g_assert (self->sorted.next == NULL);
+ g_assert (self->frame.prev == NULL);
+ g_assert (self->frame.next == NULL);
+ g_assert (self->main.prev == NULL);
+ g_assert (self->main.next == NULL);
+
+ GDK_END_MACOS_ALLOC_POOL;
+}
+
+static void
+gdk_macos_surface_constructed (GObject *object)
+{
+ GdkMacosSurface *self = (GdkMacosSurface *)object;
+ GdkFrameClock *frame_clock;
+
+ g_assert (GDK_IS_MACOS_SURFACE (self));
+
+ G_OBJECT_CLASS (gdk_macos_surface_parent_class)->constructed (object);
+
+ if (self->window != NULL)
+ {
+ NSRect bounds = [[self->window contentView] bounds];
+
+ GDK_SURFACE (self)->width = bounds.size.width;
+ GDK_SURFACE (self)->height = bounds.size.height;
+ _gdk_macos_surface_update_position (self);
+ }
+
+ if ((frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self))))
+ {
+ g_signal_connect_object (frame_clock,
+ "before-paint",
+ G_CALLBACK (gdk_macos_surface_before_paint),
+ self,
+ G_CONNECT_SWAPPED);
+ g_signal_connect_object (frame_clock,
+ "after-paint",
+ G_CALLBACK (gdk_macos_surface_after_paint),
+ self,
+ G_CONNECT_SWAPPED);
+ }
+}
+
+static void
+gdk_macos_surface_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdkMacosSurface *self = GDK_MACOS_SURFACE (object);
+
+ switch (prop_id)
+ {
+ case PROP_NATIVE:
+ g_value_set_pointer (value, self->window);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gdk_macos_surface_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdkMacosSurface *self = GDK_MACOS_SURFACE (object);
+
+ switch (prop_id)
+ {
+ case PROP_NATIVE:
+ self->window = g_value_get_pointer (value);
+ [self->window setGdkSurface:self];
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gdk_macos_surface_class_init (GdkMacosSurfaceClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GdkSurfaceClass *surface_class = GDK_SURFACE_CLASS (klass);
+
+ object_class->constructed = gdk_macos_surface_constructed;
+ object_class->get_property = gdk_macos_surface_get_property;
+ object_class->set_property = gdk_macos_surface_set_property;
+
+ surface_class->create_gl_context = gdk_macos_surface_create_gl_context;
+ surface_class->destroy = gdk_macos_surface_destroy;
+ surface_class->drag_begin = gdk_macos_surface_drag_begin;
+ surface_class->get_device_state = gdk_macos_surface_get_device_state;
+ surface_class->get_geometry = gdk_macos_surface_get_geometry;
+ surface_class->get_root_coords = gdk_macos_surface_get_root_coords;
+ surface_class->get_scale_factor = gdk_macos_surface_get_scale_factor;
+ surface_class->hide = gdk_macos_surface_hide;
+ surface_class->set_input_region = gdk_macos_surface_set_input_region;
+ surface_class->set_opaque_region = gdk_macos_surface_set_opaque_region;
+ surface_class->set_shadow_width = gdk_macos_surface_set_shadow_width;
+
+ properties [PROP_NATIVE] =
+ g_param_spec_pointer ("native",
+ "Native",
+ "The native NSWindow",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, LAST_PROP, properties);
+}
+
+static void
+gdk_macos_surface_init (GdkMacosSurface *self)
+{
+ self->frame.data = self;
+ self->main.data = self;
+ self->sorted.data = self;
+ self->monitors = g_ptr_array_new_with_free_func (g_object_unref);
+}
+
+GdkMacosSurface *
+_gdk_macos_surface_new (GdkMacosDisplay *display,
+ GdkSurfaceType surface_type,
+ GdkSurface *parent,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ GdkFrameClock *frame_clock;
+ GdkMacosSurface *ret;
+
+ g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (display), NULL);
+
+ if (parent != NULL)
+ frame_clock = g_object_ref (gdk_surface_get_frame_clock (parent));
+ else
+ frame_clock = _gdk_frame_clock_idle_new ();
+
+ switch (surface_type)
+ {
+ case GDK_SURFACE_TOPLEVEL:
+ ret = _gdk_macos_toplevel_surface_new (display, parent, frame_clock, x, y, width, height);
+ break;
+
+ case GDK_SURFACE_POPUP:
+ ret = _gdk_macos_popup_surface_new (display, parent, frame_clock, x, y, width, height);
+ break;
+
+ case GDK_SURFACE_TEMP:
+ ret = _gdk_macos_drag_surface_new (display, frame_clock, x, y, width, height);
+ break;
+
+ default:
+ g_warn_if_reached ();
+ ret = NULL;
+ }
+
+ if (ret != NULL)
+ _gdk_macos_surface_monitor_changed (ret);
+
+ g_object_unref (frame_clock);
+
+ return g_steal_pointer (&ret);
+}
+
+void
+_gdk_macos_surface_get_shadow (GdkMacosSurface *self,
+ gint *top,
+ gint *right,
+ gint *bottom,
+ gint *left)
+{
+
+ g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
+
+ if (top)
+ *top = self->shadow_top;
+
+ if (left)
+ *left = self->shadow_left;
+
+ if (bottom)
+ *bottom = self->shadow_bottom;
+
+ if (right)
+ *right = self->shadow_right;
+}
+
+const char *
+_gdk_macos_surface_get_title (GdkMacosSurface *self)
+{
+
+ return self->title;
+}
+
+void
+_gdk_macos_surface_set_title (GdkMacosSurface *self,
+ const gchar *title)
+{
+ g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
+
+ if (title == NULL)
+ title = "";
+
+ if (g_strcmp0 (self->title, title) != 0)
+ {
+ g_free (self->title);
+ self->title = g_strdup (title);
+
+ GDK_BEGIN_MACOS_ALLOC_POOL;
+ [self->window setTitle:[NSString stringWithUTF8String:title]];
+ GDK_END_MACOS_ALLOC_POOL;
+ }
+}
+
+CGDirectDisplayID
+_gdk_macos_surface_get_screen_id (GdkMacosSurface *self)
+{
+ g_return_val_if_fail (GDK_IS_MACOS_SURFACE (self), (CGDirectDisplayID)-1);
+
+ if (self->window != NULL)
+ {
+ NSScreen *screen = [self->window screen];
+ return [[[screen deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue];
+ }
+
+ return (CGDirectDisplayID)-1;
+}
+
+NSWindow *
+_gdk_macos_surface_get_native (GdkMacosSurface *self)
+{
+ g_return_val_if_fail (GDK_IS_MACOS_SURFACE (self), NULL);
+
+ return (NSWindow *)self->window;
+}
+
+void
+_gdk_macos_surface_set_geometry_hints (GdkMacosSurface *self,
+ const GdkGeometry *geometry,
+ GdkSurfaceHints geom_mask)
+{
+ NSSize max_size;
+ NSSize min_size;
+
+ g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
+ g_return_if_fail (geometry != NULL);
+ g_return_if_fail (self->window != NULL);
+
+ if (geom_mask & GDK_HINT_POS) { /* TODO */ }
+ if (geom_mask & GDK_HINT_USER_POS) { /* TODO */ }
+ if (geom_mask & GDK_HINT_USER_SIZE) { /* TODO */ }
+
+ if (geom_mask & GDK_HINT_MAX_SIZE)
+ max_size = NSMakeSize (geometry->max_width, geometry->max_height);
+ else
+ max_size = NSMakeSize (FLT_MAX, FLT_MAX);
+ [self->window setContentMaxSize:max_size];
+
+ if (geom_mask & GDK_HINT_MIN_SIZE)
+ min_size = NSMakeSize (geometry->min_width, geometry->min_height);
+ else
+ min_size = NSMakeSize (1, 1);
+ [self->window setContentMinSize:min_size];
+
+ if (geom_mask & GDK_HINT_BASE_SIZE) { /* TODO */ }
+
+ if (geom_mask & GDK_HINT_RESIZE_INC)
+ {
+ NSSize size = NSMakeSize (geometry->width_inc, geometry->height_inc);
+ [self->window setContentResizeIncrements:size];
+ }
+
+ if (geom_mask & GDK_HINT_ASPECT)
+ {
+ NSSize size;
+
+ if (geometry->min_aspect != geometry->max_aspect)
+ g_warning ("Only equal minimum and maximum aspect ratios are supported on Mac OS. Using minimum aspect ratio...");
+
+ size.width = geometry->min_aspect;
+ size.height = 1.0;
+
+ [self->window setContentAspectRatio:size];
+ }
+
+ if (geom_mask & GDK_HINT_WIN_GRAVITY) { /* TODO */ }
+}
+
+void
+_gdk_macos_surface_resize (GdkMacosSurface *self,
+ int width,
+ int height)
+{
+ g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
+
+ _gdk_macos_surface_move_resize (self, -1, -1, width, height);
+}
+
+void
+_gdk_macos_surface_update_fullscreen_state (GdkMacosSurface *self)
+{
+ GdkSurfaceState state;
+ gboolean is_fullscreen;
+ gboolean was_fullscreen;
+
+ g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
+
+ state = GDK_SURFACE (self)->state;
+ is_fullscreen = window_is_fullscreen (self);
+ was_fullscreen = (state & GDK_SURFACE_STATE_FULLSCREEN) != 0;
+
+ if (is_fullscreen != was_fullscreen)
+ {
+ if (is_fullscreen)
+ gdk_synthesize_surface_state (GDK_SURFACE (self), 0, GDK_SURFACE_STATE_FULLSCREEN);
+ else
+ gdk_synthesize_surface_state (GDK_SURFACE (self), GDK_SURFACE_STATE_FULLSCREEN, 0);
+ }
+}
+
+void
+_gdk_macos_surface_update_position (GdkMacosSurface *self)
+{
+ GdkSurface *surface = GDK_SURFACE (self);
+ GdkDisplay *display = gdk_surface_get_display (surface);
+ NSRect frame_rect = [self->window frame];
+ NSRect content_rect = [self->window contentRectForFrameRect:frame_rect];
+
+ _gdk_macos_display_from_display_coords (GDK_MACOS_DISPLAY (display),
+ content_rect.origin.x,
+ content_rect.origin.y + content_rect.size.height,
+ &self->root_x, &self->root_y);
+
+ if (surface->parent != NULL)
+ {
+ surface->x = self->root_x - GDK_MACOS_SURFACE (surface->parent)->root_x;
+ surface->y = self->root_y - GDK_MACOS_SURFACE (surface->parent)->root_y;
+ }
+ else
+ {
+ surface->x = self->root_x;
+ surface->y = self->root_y;
+ }
+}
+
+void
+_gdk_macos_surface_thaw (GdkMacosSurface *self,
+ gint64 presentation_time,
+ gint64 refresh_interval)
+{
+ GdkFrameTimings *timings;
+ GdkFrameClock *frame_clock;
+
+ g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
+
+ gdk_surface_thaw_updates (GDK_SURFACE (self));
+
+ frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self));
+
+ if (self->pending_frame_counter)
+ {
+ timings = gdk_frame_clock_get_timings (frame_clock, self->pending_frame_counter);
+
+ if (timings != NULL)
+ timings->presentation_time = presentation_time - refresh_interval;
+
+ self->pending_frame_counter = 0;
+ }
+
+ timings = gdk_frame_clock_get_current_timings (frame_clock);
+
+ if (timings != NULL)
+ {
+ timings->refresh_interval = refresh_interval;
+ timings->predicted_presentation_time = presentation_time;
+ }
+}
+
+void
+_gdk_macos_surface_show (GdkMacosSurface *self)
+{
+ gboolean was_mapped;
+
+ g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
+
+ if (GDK_SURFACE_DESTROYED (self))
+ return;
+
+ was_mapped = GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self));
+
+ if (!was_mapped)
+ gdk_synthesize_surface_state (GDK_SURFACE (self), GDK_SURFACE_STATE_WITHDRAWN, 0);
+
+ _gdk_macos_display_clear_sorting (GDK_MACOS_DISPLAY (GDK_SURFACE (self)->display));
+
+ [self->window showAndMakeKey:YES];
+
+ if (!was_mapped)
+ {
+ if (gdk_surface_get_mapped (GDK_SURFACE (self)))
+ {
+ _gdk_macos_surface_update_position (self);
+ gdk_surface_invalidate_rect (GDK_SURFACE (self), NULL);
+ }
+ }
+
+ [[self->window contentView] setNeedsDisplay:YES];
+}
+
+CGContextRef
+_gdk_macos_surface_acquire_context (GdkMacosSurface *self,
+ gboolean clear_scale,
+ gboolean antialias)
+{
+ CGContextRef cg_context;
+
+ g_return_val_if_fail (GDK_IS_MACOS_SURFACE (self), NULL);
+
+ if (GDK_SURFACE_DESTROYED (self))
+ return NULL;
+
+ if (!(cg_context = [[NSGraphicsContext currentContext] CGContext]))
+ return NULL;
+
+ CGContextSaveGState (cg_context);
+
+ if (!antialias)
+ CGContextSetAllowsAntialiasing (cg_context, antialias);
+
+ if (clear_scale)
+ {
+ CGSize scale;
+
+ scale = CGSizeMake (1.0, 1.0);
+ scale = CGContextConvertSizeToDeviceSpace (cg_context, scale);
+
+ CGContextScaleCTM (cg_context, 1.0 / scale.width, 1.0 / scale.height);
+ }
+
+ return cg_context;
+}
+
+void
+_gdk_macos_surface_release_context (GdkMacosSurface *self,
+ CGContextRef cg_context)
+{
+ g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
+
+ CGContextRestoreGState (cg_context);
+ CGContextSetAllowsAntialiasing (cg_context, TRUE);
+}
+
+void
+_gdk_macos_surface_synthesize_null_key (GdkMacosSurface *self)
+{
+ GdkTranslatedKey translated = {0};
+ GdkTranslatedKey no_lock = {0};
+ GdkDisplay *display;
+ GdkEvent *event;
+ GdkSeat *seat;
+
+ g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
+
+ translated.keyval = GDK_KEY_VoidSymbol;
+ no_lock.keyval = GDK_KEY_VoidSymbol;
+
+ display = gdk_surface_get_display (GDK_SURFACE (self));
+ seat = gdk_display_get_default_seat (display);
+ event = gdk_key_event_new (GDK_KEY_PRESS,
+ GDK_SURFACE (self),
+ gdk_seat_get_keyboard (seat),
+ NULL,
+ GDK_CURRENT_TIME,
+ 0,
+ 0,
+ FALSE,
+ &translated,
+ &no_lock);
+ _gdk_event_queue_append (display, event);
+}
+
+void
+_gdk_macos_surface_move (GdkMacosSurface *self,
+ int x,
+ int y)
+{
+ g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
+
+ _gdk_macos_surface_move_resize (self, x, y, -1, -1);
+}
+
+void
+_gdk_macos_surface_move_resize (GdkMacosSurface *self,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ GdkSurface *surface = (GdkSurface *)self;
+ GdkDisplay *display;
+ NSRect content_rect;
+ NSRect frame_rect;
+ gboolean size_changed;
+
+ g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
+
+ if ((x == -1 || (x == self->root_x)) &&
+ (y == -1 || (y == self->root_y)) &&
+ (width == -1 || (width == surface->width)) &&
+ (height == -1 || (height == surface->height)))
+ return;
+
+ display = gdk_surface_get_display (surface);
+
+ if (width == -1)
+ width = surface->width;
+
+ if (height == -1)
+ height = surface->height;
+
+ if (x == -1)
+ x = self->root_x;
+
+ if (y == -1)
+ y = self->root_y;
+
+ size_changed = height != surface->height || width != surface->width;
+
+ if (GDK_IS_MACOS_SURFACE (surface->parent))
+ {
+ surface->x = x - GDK_MACOS_SURFACE (surface->parent)->root_x;
+ surface->y = y - GDK_MACOS_SURFACE (surface->parent)->root_y;
+ }
+ else
+ {
+ surface->x = x;
+ surface->y = y;
+ }
+
+ _gdk_macos_display_to_display_coords (GDK_MACOS_DISPLAY (display),
+ x, y + height, &x, &y);
+
+ content_rect = NSMakeRect (x, y, width, height);
+ frame_rect = [self->window frameRectForContentRect:content_rect];
+ [self->window setFrame:frame_rect display:YES];
+
+ if (size_changed)
+ gdk_surface_invalidate_rect (surface, NULL);
+}
+
+gboolean
+_gdk_macos_surface_is_tracking (GdkMacosSurface *self,
+ NSTrackingArea *area)
+{
+ GdkMacosBaseView *view;
+
+ g_return_val_if_fail (GDK_IS_MACOS_SURFACE (self), FALSE);
+
+ if (self->window == NULL)
+ return FALSE;
+
+ view = (GdkMacosBaseView *)[self->window contentView];
+ if (view == NULL)
+ return FALSE;
+
+ return [view trackingArea] == area;
+}
+
+void
+_gdk_macos_surface_monitor_changed (GdkMacosSurface *self)
+{
+ GListModel *monitors;
+ GdkRectangle rect;
+ GdkRectangle intersect;
+ GdkDisplay *display;
+ GdkMonitor *monitor;
+ guint n_monitors;
+
+ g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
+
+ rect.x = self->root_x;
+ rect.y = self->root_y;
+ rect.width = GDK_SURFACE (self)->width;
+ rect.height = GDK_SURFACE (self)->height;
+
+ for (guint i = self->monitors->len; i > 0; i--)
+ {
+ monitor = g_ptr_array_index (self->monitors, i-1);
+
+ if (!gdk_rectangle_intersect (&monitor->geometry, &rect, &intersect))
+ {
+ g_object_ref (monitor);
+ g_ptr_array_remove_index (self->monitors, i-1);
+ gdk_surface_leave_monitor (GDK_SURFACE (self), monitor);
+ g_object_unref (monitor);
+ }
+ }
+
+ display = gdk_surface_get_display (GDK_SURFACE (self));
+ monitors = gdk_display_get_monitors (display);
+ n_monitors = g_list_model_get_n_items (monitors);
+
+ for (guint i = 0; i < n_monitors; i++)
+ {
+ monitor = g_list_model_get_item (monitors, i);
+
+ if (!g_ptr_array_find (self->monitors, monitor, NULL))
+ {
+ gdk_surface_enter_monitor (GDK_SURFACE (self), monitor);
+ g_ptr_array_add (self->monitors, g_object_ref (monitor));
+ }
+
+ g_object_unref (monitor);
+ }
+}
+
+GdkMonitor *
+_gdk_macos_surface_get_best_monitor (GdkMacosSurface *self)
+{
+ GdkMonitor *best = NULL;
+ GdkRectangle rect;
+ int best_area = 0;
+
+ g_return_val_if_fail (GDK_IS_MACOS_SURFACE (self), NULL);
+
+ rect.x = self->root_x;
+ rect.y = self->root_y;
+ rect.width = GDK_SURFACE (self)->width;
+ rect.height = GDK_SURFACE (self)->height;
+
+ for (guint i = 0; i < self->monitors->len; i++)
+ {
+ GdkMonitor *monitor = g_ptr_array_index (self->monitors, i);
+ GdkRectangle intersect;
+
+ if (gdk_rectangle_intersect (&monitor->geometry, &rect, &intersect))
+ {
+ int area = intersect.width * intersect.height;
+
+ if (area > best_area)
+ {
+ best = monitor;
+ best_area = area;
+ }
+ }
+ }
+
+ return best;
+}
+
+NSView *
+_gdk_macos_surface_get_view (GdkMacosSurface *self)
+{
+ g_return_val_if_fail (GDK_IS_MACOS_SURFACE (self), NULL);
+
+ if (self->window == NULL)
+ return NULL;
+
+ return [self->window contentView];
+}
+
+void
+_gdk_macos_surface_set_opacity (GdkMacosSurface *self,
+ double opacity)
+{
+ g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
+
+ if (self->window != NULL)
+ [self->window setAlphaValue:opacity];
+}
+
+void
+_gdk_macos_surface_get_root_coords (GdkMacosSurface *self,
+ int *x,
+ int *y)
+{
+ GdkSurface *surface;
+ int out_x = 0;
+ int out_y = 0;
+
+ g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
+
+ for (surface = GDK_SURFACE (self); surface; surface = surface->parent)
+ {
+ out_x += surface->x;
+ out_y += surface->y;
+ }
+
+ if (x)
+ *x = out_x;
+
+ if (y)
+ *y = out_y;
+}
--- /dev/null
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef __GDK_MACOS_SURFACE_H__
+#define __GDK_MACOS_SURFACE_H__
+
+#if !defined (__GDKMACOS_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gdk/macos/gdkmacos.h> can be included directly."
+#endif
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GdkMacosSurface GdkMacosSurface;
+typedef struct _GdkMacosSurfaceClass GdkMacosSurfaceClass;
+
+#define GDK_TYPE_MACOS_SURFACE (gdk_macos_surface_get_type())
+#define GDK_MACOS_SURFACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_MACOS_SURFACE, GdkMacosSurface))
+#define GDK_IS_MACOS_SURFACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MACOS_SURFACE))
+
+GDK_AVAILABLE_IN_ALL
+GType gdk_macos_surface_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GDK_MACOS_SURFACE_H__ */
--- /dev/null
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef __GDK_MACOS_TOPLEVEL_SURFACE_PRIVATE_H__
+#define __GDK_MACOS_TOPLEVEL_SURFACE_PRIVATE_H__
+
+#include "gdkmacossurface-private.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GdkMacosToplevelSurface GdkMacosToplevelSurface;
+typedef struct _GdkMacosToplevelSurfaceClass GdkMacosToplevelSurfaceClass;
+
+#define GDK_TYPE_MACOS_TOPLEVEL_SURFACE (_gdk_macos_toplevel_surface_get_type())
+#define GDK_MACOS_TOPLEVEL_SURFACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_MACOS_TOPLEVEL_SURFACE, GdkMacosToplevelSurface))
+#define GDK_IS_MACOS_TOPLEVEL_SURFACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MACOS_TOPLEVEL_SURFACE))
+
+GType _gdk_macos_toplevel_surface_get_type (void);
+GdkMacosSurface *_gdk_macos_toplevel_surface_new (GdkMacosDisplay *display,
+ GdkSurface *parent,
+ GdkFrameClock *frame_clock,
+ int x,
+ int y,
+ int width,
+ int height);
+void _gdk_macos_toplevel_surface_attach_to_parent (GdkMacosToplevelSurface *self);
+void _gdk_macos_toplevel_surface_detach_from_parent (GdkMacosToplevelSurface *self);
+
+G_END_DECLS
+
+#endif /* __GDK_MACOS_TOPLEVEL_SURFACE_PRIVATE_H__ */
--- /dev/null
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#import "GdkMacosWindow.h"
+
+#include "gdkinternals.h"
+#include "gdktoplevelprivate.h"
+
+#include "gdkmacosdisplay-private.h"
+#include "gdkmacostoplevelsurface-private.h"
+#include "gdkmacosutils-private.h"
+
+struct _GdkMacosToplevelSurface
+{
+ GdkMacosSurface parent_instance;
+ guint decorated : 1;
+};
+
+struct _GdkMacosToplevelSurfaceClass
+{
+ GdkMacosSurfaceClass parent_instance;
+};
+
+static void
+_gdk_macos_toplevel_surface_fullscreen (GdkMacosToplevelSurface *self)
+{
+ NSWindow *window;
+
+ g_assert (GDK_IS_MACOS_TOPLEVEL_SURFACE (self));
+
+ window = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (self));
+
+ if (([window styleMask] & NSWindowStyleMaskFullScreen) == 0)
+ [window toggleFullScreen:window];
+}
+
+static void
+_gdk_macos_toplevel_surface_unfullscreen (GdkMacosToplevelSurface *self)
+{
+ NSWindow *window;
+
+ g_assert (GDK_IS_MACOS_TOPLEVEL_SURFACE (self));
+
+ window = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (self));
+
+ if (([window styleMask] & NSWindowStyleMaskFullScreen) != 0)
+ [window toggleFullScreen:window];
+}
+
+static void
+_gdk_macos_toplevel_surface_maximize (GdkMacosToplevelSurface *self)
+{
+ NSWindow *window;
+
+ g_assert (GDK_IS_MACOS_TOPLEVEL_SURFACE (self));
+
+ window = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (self));
+
+ if (![window isZoomed])
+ [window zoom:window];
+}
+
+static void
+_gdk_macos_toplevel_surface_unmaximize (GdkMacosToplevelSurface *self)
+{
+ NSWindow *window;
+
+ g_assert (GDK_IS_MACOS_TOPLEVEL_SURFACE (self));
+
+ window = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (self));
+
+ if ([window isZoomed])
+ [window zoom:window];
+}
+
+static gboolean
+_gdk_macos_toplevel_surface_present (GdkToplevel *toplevel,
+ int width,
+ int height,
+ GdkToplevelLayout *layout)
+{
+ GdkMacosToplevelSurface *self = (GdkMacosToplevelSurface *)toplevel;
+ NSWindow *nswindow = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (self));
+ GdkGeometry geometry;
+ GdkSurfaceHints mask;
+ NSWindowStyleMask style_mask;
+
+ g_assert (GDK_IS_MACOS_TOPLEVEL_SURFACE (self));
+ g_assert (GDK_IS_MACOS_WINDOW (nswindow));
+
+ style_mask = [nswindow styleMask];
+
+ if (gdk_toplevel_layout_get_resizable (layout))
+ {
+ geometry.min_width = gdk_toplevel_layout_get_min_width (layout);
+ geometry.min_height = gdk_toplevel_layout_get_min_height (layout);
+ mask = GDK_HINT_MIN_SIZE;
+
+ /* Only set 'Resizable' mask to get native resize zones if the window is
+ * titled, otherwise we do this internally for CSD and do not need
+ * NSWindow to do it for us. Additionally, it can mess things up when
+ * doing a window resize since it can cause mouseDown to get passed
+ * through to the next window.
+ */
+ if ((style_mask & NSWindowStyleMaskTitled) != 0)
+ style_mask |= NSWindowStyleMaskResizable;
+ else
+ style_mask &= ~NSWindowStyleMaskResizable;
+ }
+ else
+ {
+ geometry.max_width = geometry.min_width = width;
+ geometry.max_height = geometry.min_height = height;
+ mask = GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE;
+
+ style_mask &= ~NSWindowStyleMaskResizable;
+ }
+
+ if (style_mask != [nswindow styleMask])
+ [nswindow setStyleMask:style_mask];
+
+ _gdk_macos_surface_set_geometry_hints (GDK_MACOS_SURFACE (self), &geometry, mask);
+ gdk_surface_constrain_size (&geometry, mask, width, height, &width, &height);
+ _gdk_macos_surface_resize (GDK_MACOS_SURFACE (self), width, height);
+
+ /* Maximized state */
+ if (gdk_toplevel_layout_get_maximized (layout))
+ _gdk_macos_toplevel_surface_maximize (self);
+ else
+ _gdk_macos_toplevel_surface_unmaximize (self);
+
+ /* Fullscreen state */
+ if (gdk_toplevel_layout_get_fullscreen (layout))
+ _gdk_macos_toplevel_surface_fullscreen (self);
+ else
+ _gdk_macos_toplevel_surface_unfullscreen (self);
+
+ if (GDK_SURFACE (self)->transient_for != NULL)
+ {
+ }
+ else
+ {
+ if (!self->decorated &&
+ !GDK_MACOS_SURFACE (self)->did_initial_present &&
+ GDK_SURFACE (self)->x == 0 &&
+ GDK_SURFACE (self)->y == 0 &&
+ (GDK_MACOS_SURFACE (self)->shadow_left ||
+ GDK_MACOS_SURFACE (self)->shadow_top))
+ {
+ GdkMonitor *monitor = _gdk_macos_surface_get_best_monitor (GDK_MACOS_SURFACE (self));
+ int x = GDK_SURFACE (self)->x;
+ int y = GDK_SURFACE (self)->y;
+
+ if (monitor != NULL)
+ {
+ GdkRectangle visible;
+
+ gdk_monitor_get_workarea (monitor, &visible);
+
+ if (x < visible.x)
+ x = visible.x;
+
+ if (y < visible.y)
+ y = visible.y;
+ }
+
+ x -= GDK_MACOS_SURFACE (self)->shadow_left;
+ y -= GDK_MACOS_SURFACE (self)->shadow_top;
+
+ _gdk_macos_surface_move (GDK_MACOS_SURFACE (self), x, y);
+ }
+ }
+
+ _gdk_macos_surface_show (GDK_MACOS_SURFACE (self));
+
+ GDK_MACOS_SURFACE (self)->did_initial_present = TRUE;
+
+ return TRUE;
+}
+
+static gboolean
+_gdk_macos_toplevel_surface_minimize (GdkToplevel *toplevel)
+{
+ GdkMacosToplevelSurface *self = (GdkMacosToplevelSurface *)toplevel;
+ NSWindow *window = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (self));
+ [window miniaturize:window];
+ return TRUE;
+}
+
+static gboolean
+_gdk_macos_toplevel_surface_lower (GdkToplevel *toplevel)
+{
+ GdkMacosToplevelSurface *self = (GdkMacosToplevelSurface *)toplevel;
+ NSWindow *window = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (self));
+ [window orderBack:window];
+ return TRUE;
+}
+
+static void
+_gdk_macos_toplevel_surface_focus (GdkToplevel *toplevel,
+ guint32 timestamp)
+{
+ GdkMacosToplevelSurface *self = (GdkMacosToplevelSurface *)toplevel;
+ NSWindow *nswindow;
+
+ if (GDK_SURFACE_DESTROYED (self))
+ return;
+
+ nswindow = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (self));
+ [nswindow makeKeyAndOrderFront:nswindow];
+}
+
+static void
+_gdk_macos_toplevel_surface_begin_resize (GdkToplevel *toplevel,
+ GdkSurfaceEdge edge,
+ GdkDevice *device,
+ int button,
+ double root_x,
+ double root_y,
+ guint32 timestamp)
+{
+ NSWindow *nswindow;
+
+ g_assert (GDK_IS_MACOS_SURFACE (toplevel));
+
+ if (GDK_SURFACE_DESTROYED (toplevel))
+ return;
+
+ /* Release passive grab */
+ if (button != 0)
+ gdk_seat_ungrab (gdk_device_get_seat (device));
+
+ if ((nswindow = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (toplevel))))
+ [(GdkMacosWindow *)nswindow beginManualResize:edge];
+}
+
+static void
+_gdk_macos_toplevel_surface_begin_move (GdkToplevel *toplevel,
+ GdkDevice *device,
+ int button,
+ double root_x,
+ double root_y,
+ guint32 timestamp)
+{
+ NSWindow *nswindow;
+
+ g_assert (GDK_IS_MACOS_SURFACE (toplevel));
+
+ if (GDK_SURFACE_DESTROYED (toplevel))
+ return;
+
+ /* Release passive grab */
+ if (button != 0)
+ gdk_seat_ungrab (gdk_device_get_seat (device));
+
+ if ((nswindow = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (toplevel))))
+ [(GdkMacosWindow *)nswindow beginManualMove];
+}
+
+
+static void
+toplevel_iface_init (GdkToplevelInterface *iface)
+{
+ iface->present = _gdk_macos_toplevel_surface_present;
+ iface->minimize = _gdk_macos_toplevel_surface_minimize;
+ iface->lower = _gdk_macos_toplevel_surface_lower;
+ iface->focus = _gdk_macos_toplevel_surface_focus;
+ iface->begin_resize = _gdk_macos_toplevel_surface_begin_resize;
+ iface->begin_move = _gdk_macos_toplevel_surface_begin_move;
+}
+
+G_DEFINE_TYPE_WITH_CODE (GdkMacosToplevelSurface, _gdk_macos_toplevel_surface, GDK_TYPE_MACOS_SURFACE,
+ G_IMPLEMENT_INTERFACE (GDK_TYPE_TOPLEVEL, toplevel_iface_init))
+
+enum {
+ PROP_0,
+ LAST_PROP
+};
+
+static void
+_gdk_macos_toplevel_surface_set_transient_for (GdkMacosToplevelSurface *self,
+ GdkMacosSurface *parent)
+{
+ g_assert (GDK_IS_MACOS_TOPLEVEL_SURFACE (self));
+ g_assert (!parent || GDK_IS_MACOS_SURFACE (parent));
+
+ _gdk_macos_toplevel_surface_detach_from_parent (self);
+ g_clear_object (&GDK_SURFACE (self)->transient_for);
+
+ if (g_set_object (&GDK_SURFACE (self)->transient_for, GDK_SURFACE (parent)))
+ _gdk_macos_toplevel_surface_attach_to_parent (self);
+}
+
+static void
+_gdk_macos_toplevel_surface_set_decorated (GdkMacosToplevelSurface *self,
+ gboolean decorated)
+{
+ g_assert (GDK_IS_MACOS_TOPLEVEL_SURFACE (self));
+
+ decorated = !!decorated;
+
+ if (decorated != self->decorated)
+ {
+ NSWindow *window = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (self));
+ self->decorated = decorated;
+ [(GdkMacosWindow *)window setDecorated:(BOOL)decorated];
+ }
+}
+
+static void
+_gdk_macos_toplevel_surface_hide (GdkSurface *surface)
+{
+ GdkMacosToplevelSurface *self = (GdkMacosToplevelSurface *)surface;
+
+ _gdk_macos_toplevel_surface_detach_from_parent (self);
+
+ GDK_SURFACE_CLASS (_gdk_macos_toplevel_surface_parent_class)->hide (surface);
+}
+
+static void
+_gdk_macos_toplevel_surface_destroy (GdkSurface *surface,
+ gboolean foreign_destroy)
+{
+ GdkMacosToplevelSurface *self = (GdkMacosToplevelSurface *)surface;
+
+ g_clear_object (&GDK_SURFACE (self)->transient_for);
+
+ GDK_SURFACE_CLASS (_gdk_macos_toplevel_surface_parent_class)->destroy (surface, foreign_destroy);
+}
+
+static void
+_gdk_macos_toplevel_surface_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdkSurface *surface = GDK_SURFACE (object);
+ GdkMacosSurface *base = GDK_MACOS_SURFACE (surface);
+ GdkMacosToplevelSurface *toplevel = GDK_MACOS_TOPLEVEL_SURFACE (base);
+
+ switch (prop_id)
+ {
+ case LAST_PROP + GDK_TOPLEVEL_PROP_STATE:
+ g_value_set_flags (value, surface->state);
+ break;
+
+ case LAST_PROP + GDK_TOPLEVEL_PROP_TITLE:
+ g_value_set_string (value, _gdk_macos_surface_get_title (base));
+ break;
+
+ case LAST_PROP + GDK_TOPLEVEL_PROP_STARTUP_ID:
+ g_value_set_string (value, "");
+ break;
+
+ case LAST_PROP + GDK_TOPLEVEL_PROP_TRANSIENT_FOR:
+ g_value_set_object (value, GDK_SURFACE (toplevel)->transient_for);
+ break;
+
+ case LAST_PROP + GDK_TOPLEVEL_PROP_MODAL:
+ g_value_set_boolean (value, GDK_SURFACE (toplevel)->modal_hint);
+ break;
+
+ case LAST_PROP + GDK_TOPLEVEL_PROP_ICON_LIST:
+ g_value_set_pointer (value, NULL);
+ break;
+
+ case LAST_PROP + GDK_TOPLEVEL_PROP_DECORATED:
+ g_value_set_boolean (value, toplevel->decorated);
+ break;
+
+ case LAST_PROP + GDK_TOPLEVEL_PROP_DELETABLE:
+ break;
+
+ case LAST_PROP + GDK_TOPLEVEL_PROP_FULLSCREEN_MODE:
+ g_value_set_enum (value, surface->fullscreen_mode);
+ break;
+
+ case LAST_PROP + GDK_TOPLEVEL_PROP_SHORTCUTS_INHIBITED:
+ g_value_set_boolean (value, surface->shortcuts_inhibited);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+_gdk_macos_toplevel_surface_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdkSurface *surface = GDK_SURFACE (object);
+ GdkMacosSurface *base = GDK_MACOS_SURFACE (surface);
+ GdkMacosToplevelSurface *toplevel = GDK_MACOS_TOPLEVEL_SURFACE (base);
+
+ switch (prop_id)
+ {
+ case LAST_PROP + GDK_TOPLEVEL_PROP_TITLE:
+ _gdk_macos_surface_set_title (base, g_value_get_string (value));
+ g_object_notify_by_pspec (G_OBJECT (surface), pspec);
+ break;
+
+ case LAST_PROP + GDK_TOPLEVEL_PROP_STARTUP_ID:
+ break;
+
+ case LAST_PROP + GDK_TOPLEVEL_PROP_TRANSIENT_FOR:
+ _gdk_macos_toplevel_surface_set_transient_for (toplevel, g_value_get_object (value));
+ g_object_notify_by_pspec (G_OBJECT (surface), pspec);
+ break;
+
+ case LAST_PROP + GDK_TOPLEVEL_PROP_MODAL:
+ GDK_SURFACE (surface)->modal_hint = g_value_get_boolean (value);
+ g_object_notify_by_pspec (G_OBJECT (surface), pspec);
+ break;
+
+ case LAST_PROP + GDK_TOPLEVEL_PROP_ICON_LIST:
+ break;
+
+ case LAST_PROP + GDK_TOPLEVEL_PROP_DECORATED:
+ _gdk_macos_toplevel_surface_set_decorated (toplevel, g_value_get_boolean (value));
+ break;
+
+ case LAST_PROP + GDK_TOPLEVEL_PROP_DELETABLE:
+ break;
+
+ case LAST_PROP + GDK_TOPLEVEL_PROP_FULLSCREEN_MODE:
+ surface->fullscreen_mode = g_value_get_enum (value);
+ g_object_notify_by_pspec (G_OBJECT (surface), pspec);
+ break;
+
+ case LAST_PROP + GDK_TOPLEVEL_PROP_SHORTCUTS_INHIBITED:
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+_gdk_macos_toplevel_surface_class_init (GdkMacosToplevelSurfaceClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GdkSurfaceClass *surface_class = GDK_SURFACE_CLASS (klass);
+
+ object_class->get_property = _gdk_macos_toplevel_surface_get_property;
+ object_class->set_property = _gdk_macos_toplevel_surface_set_property;
+
+ surface_class->destroy = _gdk_macos_toplevel_surface_destroy;
+ surface_class->hide = _gdk_macos_toplevel_surface_hide;
+
+ gdk_toplevel_install_properties (object_class, LAST_PROP);
+}
+
+static void
+_gdk_macos_toplevel_surface_init (GdkMacosToplevelSurface *self)
+{
+ self->decorated = TRUE;
+}
+
+GdkMacosSurface *
+_gdk_macos_toplevel_surface_new (GdkMacosDisplay *display,
+ GdkSurface *parent,
+ GdkFrameClock *frame_clock,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ GDK_BEGIN_MACOS_ALLOC_POOL;
+
+ GdkMacosWindow *window;
+ GdkMacosSurface *self;
+ NSScreen *screen;
+ NSUInteger style_mask;
+ NSRect content_rect;
+ NSRect screen_rect;
+ int nx;
+ int ny;
+
+ g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (display), NULL);
+ g_return_val_if_fail (!frame_clock || GDK_IS_FRAME_CLOCK (frame_clock), NULL);
+ g_return_val_if_fail (!parent || GDK_IS_MACOS_SURFACE (parent), NULL);
+
+ style_mask = (NSWindowStyleMaskTitled |
+ NSWindowStyleMaskClosable |
+ NSWindowStyleMaskMiniaturizable |
+ NSWindowStyleMaskResizable);
+
+ _gdk_macos_display_to_display_coords (display, x, y, &nx, &ny);
+
+ screen = _gdk_macos_display_get_screen_at_display_coords (display, nx, ny);
+ screen_rect = [screen visibleFrame];
+ nx -= screen_rect.origin.x;
+ ny -= screen_rect.origin.y;
+ content_rect = NSMakeRect (nx, ny - height, width, height);
+
+ window = [[GdkMacosWindow alloc] initWithContentRect:content_rect
+ styleMask:style_mask
+ backing:NSBackingStoreBuffered
+ defer:NO
+ screen:screen];
+
+ self = g_object_new (GDK_TYPE_MACOS_TOPLEVEL_SURFACE,
+ "display", display,
+ "frame-clock", frame_clock,
+ "native", window,
+ NULL);
+
+ GDK_END_MACOS_ALLOC_POOL;
+
+ return g_steal_pointer (&self);
+}
+
+void
+_gdk_macos_toplevel_surface_attach_to_parent (GdkMacosToplevelSurface *self)
+{
+ GdkSurface *surface = (GdkSurface *)self;
+
+ g_return_if_fail (GDK_IS_MACOS_TOPLEVEL_SURFACE (self));
+
+ if (GDK_SURFACE_DESTROYED (surface))
+ return;
+
+ if (surface->transient_for != NULL &&
+ !GDK_SURFACE_DESTROYED (surface->transient_for))
+ {
+ NSWindow *parent = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (surface->transient_for));
+ NSWindow *window = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (self));
+
+ [parent addChildWindow:window ordered:NSWindowAbove];
+
+ if (GDK_SURFACE (self)->modal_hint)
+ [window setLevel:NSModalPanelWindowLevel];
+
+ _gdk_macos_display_clear_sorting (GDK_MACOS_DISPLAY (surface->display));
+ }
+}
+
+void
+_gdk_macos_toplevel_surface_detach_from_parent (GdkMacosToplevelSurface *self)
+{
+ GdkSurface *surface = (GdkSurface *)self;
+
+ g_return_if_fail (GDK_IS_MACOS_TOPLEVEL_SURFACE (self));
+
+ if (GDK_SURFACE_DESTROYED (surface))
+ return;
+
+ if (surface->transient_for != NULL &&
+ !GDK_SURFACE_DESTROYED (surface->transient_for))
+ {
+ NSWindow *parent = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (surface->transient_for));
+ NSWindow *window = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (self));
+
+ [parent removeChildWindow:window];
+ [window setLevel:NSNormalWindowLevel];
+
+ _gdk_macos_display_clear_sorting (GDK_MACOS_DISPLAY (surface->display));
+ }
+}
--- /dev/null
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef __GDK_MACOS_UTILS_PRIVATE_H__
+#define __GDK_MACOS_UTILS_PRIVATE_H__
+
+#include <AppKit/AppKit.h>
+#include <gdk/gdk.h>
+
+#define GDK_BEGIN_MACOS_ALLOC_POOL NSAutoreleasePool *_pool = [[NSAutoreleasePool alloc] init]
+#define GDK_END_MACOS_ALLOC_POOL [_pool release]
+
+static inline gboolean
+queue_contains (GQueue *queue,
+ GList *link_)
+{
+ return queue->head == link_ || link_->prev || link_->next;
+}
+
+#endif /* __GDK_MACOS_UTILS_PRIVATE_H__ */
--- /dev/null
+gdk_macos_sources = files([
+ 'edgesnapping.c',
+
+ 'gdkdisplaylinksource.c',
+ 'gdkmacoscairocontext.c',
+ 'gdkmacosclipboard.c',
+ 'gdkmacoscursor.c',
+ 'gdkmacosdevice.c',
+ 'gdkmacosdisplay.c',
+ 'gdkmacosdisplay-settings.c',
+ 'gdkmacosdisplay-translate.c',
+ 'gdkmacosdrag.c',
+ 'gdkmacosdragsurface.c',
+ 'gdkmacosglcontext.c',
+ 'gdkmacoseventsource.c',
+ 'gdkmacoskeymap.c',
+ 'gdkmacosmonitor.c',
+ 'gdkmacospopupsurface.c',
+ 'gdkmacosseat.c',
+ 'gdkmacossurface.c',
+ 'gdkmacostoplevelsurface.c',
+
+ 'GdkMacosBaseView.c',
+ 'GdkMacosCairoView.c',
+ 'GdkMacosCairoSubview.c',
+ 'GdkMacosGLLayer.c',
+ 'GdkMacosWindow.c',
+])
+
+gdk_macos_public_headers = files([
+ 'gdkmacosdevice.h',
+ 'gdkmacosdisplay.h',
+ 'gdkmacosglcontext.h',
+ 'gdkmacoskeymap.h',
+ 'gdkmacosmonitor.h',
+ 'gdkmacossurface.h',
+])
+
+install_headers(gdk_macos_public_headers, 'gdkmacos.h', subdir: 'gtk-4.0/gdk/macos/')
+
+gdk_macos_frameworks = [
+ 'AppKit',
+ 'Carbon',
+ 'CoreVideo',
+ 'CoreServices',
+ 'OpenGL',
+ 'QuartzCore',
+]
+
+gdk_macos_deps = [
+ dependency('appleframeworks', modules: gdk_macos_frameworks)
+]
+
+libgdk_c_args += ['-xobjective-c']
+
+libgdk_macos = static_library('gdk-macos',
+ gdk_macos_sources, gdkconfig, gdkenum_h,
+ include_directories: [ confinc, gdkinc, ],
+ c_args: libgdk_c_args + common_cflags,
+ link_args: common_ldflags,
+ link_with: [],
+ dependencies: gdk_deps + gdk_macos_deps)
gdkconfig_cdata.set('GDK_WINDOWING_WAYLAND', wayland_enabled)
gdkconfig_cdata.set('GDK_WINDOWING_WIN32', win32_enabled)
gdkconfig_cdata.set('GDK_WINDOWING_BROADWAY', broadway_enabled)
+gdkconfig_cdata.set('GDK_WINDOWING_MACOS', macos_enabled)
gdkconfig_cdata.set('GDK_RENDERING_VULKAN', have_vulkan)
gdkconfig = configure_file(
gdk_backends = []
gdk_backends_gen_headers = [] # non-public generated headers
-foreach backend : ['broadway', 'quartz', 'wayland', 'win32', 'x11']
+foreach backend : ['broadway', 'quartz', 'wayland', 'win32', 'x11', 'macos']
if get_variable('@0@_enabled'.format(backend))
subdir(backend)
gdk_deps += get_variable('gdk_@0@_deps'.format(backend))
+++ /dev/null
-/* GdkQuartzSurface.m
- *
- * Copyright (C) 2005-2007 Imendio AB
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-#import "GdkQuartzNSWindow.h"
-#include "gdkquartzsurface.h"
-#include "gdkdnd-quartz.h"
-#include "gdkprivate-quartz.h"
-
-@implementation GdkQuartzNSWindow
-
-- (void)windowWillClose:(NSNotification*)notification
-{
- // Clears the delegate when window is going to be closed; since EL
- // Capitan it is possible that the methods of delegate would get
- // called after the window has been closed.
- [self setDelegate:nil];
-}
-
--(BOOL)windowShouldClose:(id)sender
-{
- GdkSurface *window = [[self contentView] gdkSurface];
- GdkEvent *event;
-
- event = gdk_event_new (GDK_DELETE);
-
- event->any.surface = g_object_ref (window);
- event->any.send_event = FALSE;
-
- _gdk_event_queue_append (gdk_display_get_default (), event);
-
- return NO;
-}
-
--(void)windowWillMiniaturize:(NSNotification *)aNotification
-{
- GdkSurface *window = [[self contentView] gdkSurface];
-
- _gdk_quartz_surface_detach_from_parent (window);
-}
-
--(void)windowDidMiniaturize:(NSNotification *)aNotification
-{
- GdkSurface *window = [[self contentView] gdkSurface];
-
- gdk_synthesize_surface_state (window, 0, GDK_SURFACE_STATE_MINIMIZED);
-}
-
--(void)windowDidDeminiaturize:(NSNotification *)aNotification
-{
- GdkSurface *window = [[self contentView] gdkSurface];
-
- _gdk_quartz_surface_attach_to_parent (window);
-
- gdk_synthesize_surface_state (window, GDK_SURFACE_STATE_MINIMIZED, 0);
-}
-
--(void)windowDidBecomeKey:(NSNotification *)aNotification
-{
- GdkSurface *window = [[self contentView] gdkSurface];
-
- gdk_synthesize_surface_state (window, 0, GDK_SURFACE_STATE_FOCUSED);
- _gdk_quartz_events_update_focus_window (window, TRUE);
-}
-
--(void)windowDidResignKey:(NSNotification *)aNotification
-{
- GdkSurface *window = [[self contentView] gdkSurface];
-
- _gdk_quartz_events_update_focus_window (window, FALSE);
- gdk_synthesize_surface_state (window, GDK_SURFACE_STATE_FOCUSED, 0);
-}
-
--(void)windowDidBecomeMain:(NSNotification *)aNotification
-{
- GdkSurface *window = [[self contentView] gdkSurface];
-
- if (![self isVisible])
- {
- /* Note: This is a hack needed because for unknown reasons, hidden
- * windows get shown when clicking the dock icon when the application
- * is not already active.
- */
- [self orderOut:nil];
- return;
- }
-
- _gdk_quartz_surface_did_become_main (window);
-}
-
--(void)windowDidResignMain:(NSNotification *)aNotification
-{
- GdkSurface *window;
-
- window = [[self contentView] gdkSurface];
- _gdk_quartz_surface_did_resign_main (window);
-}
-
-/* Used in combination with NSLeftMouseUp in sendEvent to keep track
- * of when the window is being moved with the mouse.
- */
--(void)windowWillMove:(NSNotification *)aNotification
-{
- inMove = YES;
-}
-
--(void)sendEvent:(NSEvent *)event
-{
- switch ([event type])
- {
- case NSLeftMouseUp:
- {
- double time = ((double)[event timestamp]) * 1000.0;
-
- _gdk_quartz_events_break_all_grabs (time);
- inManualMove = NO;
- inManualResize = NO;
- inMove = NO;
- break;
- }
-
- case NSLeftMouseDragged:
- if ([self trackManualMove] || [self trackManualResize])
- return;
- break;
-
- default:
- break;
- }
-
- [super sendEvent:event];
-}
-
--(BOOL)isInMove
-{
- return inMove;
-}
-
--(void)checkSendEnterNotify
-{
- GdkSurface *window = [[self contentView] gdkSurface];
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- /* When a new window has been created, and the mouse
- * is in the window area, we will not receive an NSMouseEntered
- * event. Therefore, we synthesize an enter notify event manually.
- */
- if (!initialPositionKnown)
- {
- initialPositionKnown = YES;
-
- if (NSPointInRect ([NSEvent mouseLocation], [self frame]))
- {
- NSEvent *event;
-
- event = [NSEvent enterExitEventWithType: NSMouseEntered
- location: [self mouseLocationOutsideOfEventStream]
- modifierFlags: 0
- timestamp: [[NSApp currentEvent] timestamp]
- windowNumber: [impl->toplevel windowNumber]
- context: NULL
- eventNumber: 0
- trackingNumber: [impl->view trackingRect]
- userData: nil];
-
- [NSApp postEvent:event atStart:NO];
- }
- }
-}
-
--(void)windowDidMove:(NSNotification *)aNotification
-{
- GdkSurface *window = [[self contentView] gdkSurface];
- GdkEvent *event;
-
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
- gboolean maximized = gdk_surface_get_state (window) & GDK_SURFACE_STATE_MAXIMIZED;
-
- /* In case the window is changed when maximized remove the maximized state */
- if (maximized && !inMaximizeTransition && !NSEqualRects (lastMaximizedFrame, [self frame]))
- {
- gdk_synthesize_surface_state (window,
- GDK_SURFACE_STATE_MAXIMIZED,
- 0);
- }
-
- _gdk_quartz_surface_update_position (window);
-
- /* Synthesize a configure event */
- event = gdk_event_new (GDK_CONFIGURE);
- event->configure.window = g_object_ref (window);
- event->configure.x = window->x;
- event->configure.y = window->y;
- event->configure.width = window->width;
- event->configure.height = window->height;
-
- _gdk_event_queue_append (gdk_display_get_default (), event);
-
- [self checkSendEnterNotify];
-}
-
--(void)windowDidResize:(NSNotification *)aNotification
-{
- NSRect content_rect = [self contentRectForFrameRect:[self frame]];
- GdkSurface *window = [[self contentView] gdkSurface];
- GdkEvent *event;
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
- gboolean maximized = gdk_surface_get_state (window) & GDK_SURFACE_STATE_MAXIMIZED;
-
- /* see same in windowDidMove */
- if (maximized && !inMaximizeTransition && !NSEqualRects (lastMaximizedFrame, [self frame]))
- {
- gdk_synthesize_surface_state (window,
- GDK_SURFACE_STATE_MAXIMIZED,
- 0);
- }
-
- window->width = content_rect.size.width;
- window->height = content_rect.size.height;
-
- /* Certain resize operations (e.g. going fullscreen), also move the
- * origin of the window.
- */
- _gdk_quartz_surface_update_position (window);
-
- [[self contentView] setFrame:NSMakeRect (0, 0, window->width, window->height)];
-
- _gdk_surface_update_size (window);
-
- /* Synthesize a configure event */
- event = gdk_event_new (GDK_CONFIGURE);
- event->configure.window = g_object_ref (window);
- event->configure.x = window->x;
- event->configure.y = window->y;
- event->configure.width = window->width;
- event->configure.height = window->height;
-
- _gdk_event_queue_append (gdk_display_get_default (), event);
-
- [self checkSendEnterNotify];
-}
-
--(id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask backing:(NSBackingStoreType)backingType defer:(BOOL)flag screen:(NSScreen *)screen
-{
- self = [super initWithContentRect:contentRect
- styleMask:styleMask
- backing:backingType
- defer:flag
- screen:screen];
-
- [self setAcceptsMouseMovedEvents:YES];
- [self setDelegate:self];
- [self setReleasedWhenClosed:YES];
-
- return self;
-}
-
--(BOOL)canBecomeMainWindow
-{
- GdkSurface *window = [[self contentView] gdkSurface];
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- switch (impl->type_hint)
- {
- case GDK_SURFACE_TYPE_HINT_NORMAL:
- case GDK_SURFACE_TYPE_HINT_DIALOG:
- return YES;
-
- case GDK_SURFACE_TYPE_HINT_MENU:
- case GDK_SURFACE_TYPE_HINT_TOOLBAR:
- case GDK_SURFACE_TYPE_HINT_SPLASHSCREEN:
- case GDK_SURFACE_TYPE_HINT_UTILITY:
- case GDK_SURFACE_TYPE_HINT_DOCK:
- case GDK_SURFACE_TYPE_HINT_DESKTOP:
- case GDK_SURFACE_TYPE_HINT_DROPDOWN_MENU:
- case GDK_SURFACE_TYPE_HINT_POPUP_MENU:
- case GDK_SURFACE_TYPE_HINT_TOOLTIP:
- case GDK_SURFACE_TYPE_HINT_NOTIFICATION:
- case GDK_SURFACE_TYPE_HINT_COMBO:
- case GDK_SURFACE_TYPE_HINT_DND:
- return NO;
- }
-
- return YES;
-}
-
--(BOOL)canBecomeKeyWindow
-{
- GdkSurface *window = [[self contentView] gdkSurface];
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (!window->accept_focus)
- return NO;
-
- /* Popup windows should not be able to get focused in the window
- * manager sense, it's only handled through grabs.
- */
- if (window->surface_type == GDK_SURFACE_TEMP)
- return NO;
-
- switch (impl->type_hint)
- {
- case GDK_SURFACE_TYPE_HINT_NORMAL:
- case GDK_SURFACE_TYPE_HINT_DIALOG:
- case GDK_SURFACE_TYPE_HINT_MENU:
- case GDK_SURFACE_TYPE_HINT_TOOLBAR:
- case GDK_SURFACE_TYPE_HINT_UTILITY:
- case GDK_SURFACE_TYPE_HINT_DOCK:
- case GDK_SURFACE_TYPE_HINT_DESKTOP:
- case GDK_SURFACE_TYPE_HINT_DROPDOWN_MENU:
- case GDK_SURFACE_TYPE_HINT_POPUP_MENU:
- case GDK_SURFACE_TYPE_HINT_COMBO:
- return YES;
-
- case GDK_SURFACE_TYPE_HINT_SPLASHSCREEN:
- case GDK_SURFACE_TYPE_HINT_TOOLTIP:
- case GDK_SURFACE_TYPE_HINT_NOTIFICATION:
- case GDK_SURFACE_TYPE_HINT_DND:
- return NO;
- }
-
- return YES;
-}
-
-- (void)showAndMakeKey:(BOOL)makeKey
-{
- GdkSurface *window = [[self contentView] gdkSurface];
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- inShowOrHide = YES;
-
- if (makeKey)
- [impl->toplevel makeKeyAndOrderFront:impl->toplevel];
- else
- [impl->toplevel orderFront:nil];
-
- inShowOrHide = NO;
-
- [self checkSendEnterNotify];
-}
-
-- (void)hide
-{
- GdkSurface *window = [[self contentView] gdkSurface];
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- inShowOrHide = YES;
- [impl->toplevel orderOut:nil];
- inShowOrHide = NO;
-
- initialPositionKnown = NO;
-}
-
-- (BOOL)trackManualMove
-{
- GdkSurface *window = [[self contentView] gdkSurface];
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
- NSPoint currentLocation;
- NSPoint newOrigin;
- NSRect screenFrame = [[NSScreen mainScreen] visibleFrame];
- NSRect windowFrame = [self frame];
-
- if (!inManualMove)
- return NO;
-
- currentLocation = [self convertBaseToScreen:[self mouseLocationOutsideOfEventStream]];
- newOrigin.x = currentLocation.x - initialMoveLocation.x;
- newOrigin.y = currentLocation.y - initialMoveLocation.y;
-
- /* Clamp vertical position to below the menu bar. */
- if (newOrigin.y + windowFrame.size.height - impl->shadow_top > screenFrame.origin.y + screenFrame.size.height)
- newOrigin.y = screenFrame.origin.y + screenFrame.size.height - windowFrame.size.height + impl->shadow_top;
-
- [self setFrameOrigin:newOrigin];
-
- return YES;
-}
-
-/* Used by gdkevents-quartz.c to decide if our sendEvent() handler above
- * will see the event or if it will be subjected to standard processing
- * by GDK.
-*/
--(BOOL)isInManualResizeOrMove
-{
- return inManualResize || inManualMove;
-}
-
--(void)beginManualMove
-{
- NSRect frame = [self frame];
-
- if (inMove || inManualMove || inManualResize)
- return;
-
- inManualMove = YES;
-
- initialMoveLocation = [self convertBaseToScreen:[self mouseLocationOutsideOfEventStream]];
- initialMoveLocation.x -= frame.origin.x;
- initialMoveLocation.y -= frame.origin.y;
-}
-
-- (BOOL)trackManualResize
-{
- NSPoint mouse_location;
- NSRect new_frame;
- float mdx, mdy, dw, dh, dx, dy;
- NSSize min_size;
-
- if (!inManualResize || inTrackManualResize)
- return NO;
-
- inTrackManualResize = YES;
-
- mouse_location = [self convertBaseToScreen:[self mouseLocationOutsideOfEventStream]];
- mdx = initialResizeLocation.x - mouse_location.x;
- mdy = initialResizeLocation.y - mouse_location.y;
-
- /* Set how a mouse location delta translates to changes in width,
- * height and position.
- */
- dw = dh = dx = dy = 0.0;
- if (resizeEdge == GDK_SURFACE_EDGE_EAST ||
- resizeEdge == GDK_SURFACE_EDGE_NORTH_EAST ||
- resizeEdge == GDK_SURFACE_EDGE_SOUTH_EAST)
- {
- dw = -1.0;
- }
- if (resizeEdge == GDK_SURFACE_EDGE_NORTH ||
- resizeEdge == GDK_SURFACE_EDGE_NORTH_WEST ||
- resizeEdge == GDK_SURFACE_EDGE_NORTH_EAST)
- {
- dh = -1.0;
- }
- if (resizeEdge == GDK_SURFACE_EDGE_SOUTH ||
- resizeEdge == GDK_SURFACE_EDGE_SOUTH_WEST ||
- resizeEdge == GDK_SURFACE_EDGE_SOUTH_EAST)
- {
- dh = 1.0;
- dy = -1.0;
- }
- if (resizeEdge == GDK_SURFACE_EDGE_WEST ||
- resizeEdge == GDK_SURFACE_EDGE_NORTH_WEST ||
- resizeEdge == GDK_SURFACE_EDGE_SOUTH_WEST)
- {
- dw = 1.0;
- dx = -1.0;
- }
-
- /* Apply changes to the frame captured when we started resizing */
- new_frame = initialResizeFrame;
- new_frame.origin.x += mdx * dx;
- new_frame.origin.y += mdy * dy;
- new_frame.size.width += mdx * dw;
- new_frame.size.height += mdy * dh;
-
- /* In case the resulting window would be too small reduce the
- * change to both size and position.
- */
- min_size = [self contentMinSize];
-
- if (new_frame.size.width < min_size.width)
- {
- if (dx)
- new_frame.origin.x -= min_size.width - new_frame.size.width;
- new_frame.size.width = min_size.width;
- }
-
- if (new_frame.size.height < min_size.height)
- {
- if (dy)
- new_frame.origin.y -= min_size.height - new_frame.size.height;
- new_frame.size.height = min_size.height;
- }
-
- /* We could also apply aspect ratio:
- new_frame.size.height = new_frame.size.width / [self aspectRatio].width * [self aspectRatio].height;
- */
-
- [self setFrame:new_frame display:YES];
-
- /* Let the resizing be handled by GTK+. */
- if (g_main_context_pending (NULL))
- g_main_context_iteration (NULL, FALSE);
-
- inTrackManualResize = NO;
-
- return YES;
-}
-
--(void)beginManualResize:(GdkSurfaceEdge)edge
-{
- if (inMove || inManualMove || inManualResize)
- return;
-
- inManualResize = YES;
- resizeEdge = edge;
-
- initialResizeFrame = [self frame];
- initialResizeLocation = [self convertBaseToScreen:[self mouseLocationOutsideOfEventStream]];
-}
-
-
-
-static GdkDragContext *current_context = NULL;
-
-static GdkDragAction
-drag_operation_to_drag_action (NSDragOperation operation)
-{
- GdkDragAction result = 0;
-
- /* GDK and Quartz drag operations do not map 1:1.
- * This mapping represents about the best that we
- * can come up.
- */
-
- if (operation & NSDragOperationGeneric)
- result |= GDK_ACTION_MOVE;
- if (operation & NSDragOperationCopy)
- result |= GDK_ACTION_COPY;
- if (operation & NSDragOperationMove)
- result |= GDK_ACTION_MOVE;
- if (operation & NSDragOperationLink)
- result |= GDK_ACTION_LINK;
-
- return result;
-}
-
-static NSDragOperation
-drag_action_to_drag_operation (GdkDragAction action)
-{
- NSDragOperation result = 0;
-
- if (action & GDK_ACTION_COPY)
- result |= NSDragOperationCopy;
- if (action & GDK_ACTION_LINK)
- result |= NSDragOperationLink;
- if (action & GDK_ACTION_MOVE)
- result |= NSDragOperationMove;
-
- return result;
-}
-
-static void
-update_context_from_dragging_info (id <NSDraggingInfo> sender)
-{
- GdkDragAction action;
-
- g_assert (current_context != NULL);
-
- GDK_QUARTZ_DRAG_CONTEXT (current_context)->dragging_info = sender;
- action = drag_operation_to_drag_action ([sender draggingSourceOperationMask]);
- gdk_drag_context_set_actions (current_context, action, action);
-}
-
-- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
-{
- GdkEvent *event;
- GdkSurface *window;
-
- if (current_context)
- g_object_unref (current_context);
-
- current_context = g_object_new (GDK_TYPE_QUARTZ_DRAG_CONTEXT,
- "device", gdk_seat_get_pointer (gdk_display_get_default_seat (current_context->display)),
- NULL);
- update_context_from_dragging_info (sender);
-
- window = [[self contentView] gdkSurface];
-
- event = gdk_event_new (GDK_DRAG_ENTER);
- event->dnd.window = g_object_ref (window);
- event->dnd.send_event = FALSE;
- event->dnd.context = g_object_ref (current_context);
- event->dnd.time = GDK_CURRENT_TIME;
-
- gdk_event_set_device (event, gdk_drag_context_get_device (current_context));
- gdk_event_set_seat (event, gdk_device_get_seat (gdk_drag_context_get_device (current_context)));
-
- _gdk_event_emit (event);
-
- g_object_unref (event);
-
- return NSDragOperationNone;
-}
-
-- (void)draggingEnded:(id <NSDraggingInfo>)sender
-{
- /* leave a note for the source about what action was taken */
- if (_gdk_quartz_drag_source_context && current_context)
- _gdk_quartz_drag_source_context->action = current_context->action;
-
- if (current_context)
- g_object_unref (current_context);
- current_context = NULL;
-}
-
-- (void)draggingExited:(id <NSDraggingInfo>)sender
-{
- GdkEvent *event;
-
- event = gdk_event_new (GDK_DRAG_LEAVE);
- event->dnd.window = g_object_ref ([[self contentView] gdkSurface]);
- event->dnd.send_event = FALSE;
- event->dnd.context = g_object_ref (current_context);
- event->dnd.time = GDK_CURRENT_TIME;
-
- gdk_event_set_device (event, gdk_drag_context_get_device (current_context));
- gdk_event_set_seat (event, gdk_device_get_seat (gdk_drag_context_get_device (current_context)));
-
- _gdk_event_emit (event);
-
- g_object_unref (event);
-
- g_object_unref (current_context);
- current_context = NULL;
-}
-
-- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
-{
- NSPoint point = [sender draggingLocation];
- NSPoint screen_point = [self convertBaseToScreen:point];
- GdkEvent *event;
- int gx, gy;
-
- update_context_from_dragging_info (sender);
- _gdk_quartz_surface_nspoint_to_gdk_xy (screen_point, &gx, &gy);
-
- event = gdk_event_new (GDK_DRAG_MOTION);
- event->dnd.window = g_object_ref ([[self contentView] gdkSurface]);
- event->dnd.send_event = FALSE;
- event->dnd.context = g_object_ref (current_context);
- event->dnd.time = GDK_CURRENT_TIME;
- event->dnd.x_root = gx;
- event->dnd.y_root = gy;
-
- gdk_event_set_device (event, gdk_drag_context_get_device (current_context));
- gdk_event_set_seat (event, gdk_device_get_seat (gdk_drag_context_get_device (current_context)));
-
- _gdk_event_emit (event);
-
- g_object_unref (event);
-
- return drag_action_to_drag_operation (current_context->action);
-}
-
-- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
-{
- NSPoint point = [sender draggingLocation];
- NSPoint screen_point = [self convertBaseToScreen:point];
- GdkEvent *event;
- int gy, gx;
-
- update_context_from_dragging_info (sender);
- _gdk_quartz_surface_nspoint_to_gdk_xy (screen_point, &gx, &gy);
-
- event = gdk_event_new (GDK_DROP_START);
- event->dnd.window = g_object_ref ([[self contentView] gdkSurface]);
- event->dnd.send_event = FALSE;
- event->dnd.context = g_object_ref (current_context);
- event->dnd.time = GDK_CURRENT_TIME;
- event->dnd.x_root = gx;
- event->dnd.y_root = gy;
-
- gdk_event_set_device (event, gdk_drag_context_get_device (current_context));
- gdk_event_set_seat (event, gdk_device_get_seat (gdk_drag_context_get_device (current_context)));
-
- _gdk_event_emit (event);
-
- g_object_unref (event);
-
- g_object_unref (current_context);
- current_context = NULL;
-
- return YES;
-}
-
-- (BOOL)wantsPeriodicDraggingUpdates
-{
- return NO;
-}
-
-- (void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation
-{
- GdkEvent *event;
- GdkDisplay *display;
- GdkDevice *device;
-
- g_assert (_gdk_quartz_drag_source_context != NULL);
-
- event = gdk_event_new (GDK_DROP_FINISHED);
- event->dnd.window = g_object_ref ([[self contentView] gdkSurface]);
- event->dnd.send_event = FALSE;
- event->dnd.context = g_object_ref (_gdk_quartz_drag_source_context);
-
- display = gdk_surface_get_display (event->dnd.window);
-
- if (display)
- {
- GList* windows, *list;
- gint gx, gy;
-
- event->dnd.context->dest_surface = NULL;
-
- windows = get_toplevels ();
- _gdk_quartz_surface_nspoint_to_gdk_xy (aPoint, &gx, &gy);
-
- for (list = windows; list; list = list->next)
- {
- GdkSurface* win = (GdkSurface*) list->data;
- gint wx, wy;
- gint ww, wh;
-
- gdk_surface_get_root_origin (win, &wx, &wy);
- ww = gdk_surface_get_width (win);
- wh = gdk_surface_get_height (win);
-
- if (gx > wx && gy > wy && gx <= wx + ww && gy <= wy + wh)
- event->dnd.context->dest_surface = win;
- }
- }
-
- device = gdk_drag_context_get_device (_gdk_quartz_drag_source_context);
- gdk_event_set_device (event, device);
- gdk_event_set_seat (event, gdk_device_get_seat (device));
-
- _gdk_event_emit (event);
-
- g_object_unref (event);
-
- g_object_unref (_gdk_quartz_drag_source_context);
- _gdk_quartz_drag_source_context = NULL;
-}
-
-#ifdef AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
-
-- (void)setStyleMask:(NSUInteger)styleMask
-{
- gboolean was_fullscreen;
- gboolean is_fullscreen;
-
- was_fullscreen = (([self styleMask] & NSFullScreenWindowMask) != 0);
-
- [super setStyleMask:styleMask];
-
- is_fullscreen = (([self styleMask] & NSFullScreenWindowMask) != 0);
-
- if (was_fullscreen != is_fullscreen)
- _gdk_quartz_surface_update_fullscreen_state ([[self contentView] gdkSurface]);
-}
-
-#endif
-
-- (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
-{
- NSRect rect;
- GdkSurface *window = [[self contentView] gdkSurface];
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- /* Allow the window to move up "shadow_top" more than normally allowed
- * by the default impl. This makes it possible to move windows with
- * client side shadow right up to the screen's menu bar. */
- rect = [super constrainFrameRect:frameRect toScreen:screen];
- if (frameRect.origin.y > rect.origin.y)
- rect.origin.y = MIN (frameRect.origin.y, rect.origin.y + impl->shadow_top);
-
- return rect;
-}
-
-- (NSRect)windowWillUseStandardFrame:(NSWindow *)nsWindow
- defaultFrame:(NSRect)newFrame
-{
- NSRect screenFrame = [[self screen] visibleFrame];
- GdkSurface *window = [[self contentView] gdkSurface];
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
- gboolean maximized = gdk_surface_get_state (window) & GDK_SURFACE_STATE_MAXIMIZED;
-
- if (!maximized)
- return screenFrame;
- else
- return lastUnmaximizedFrame;
-}
-
-- (BOOL)windowShouldZoom:(NSWindow *)nsWindow
- toFrame:(NSRect)newFrame
-{
-
- GdkSurface *window = [[self contentView] gdkSurface];
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
- gboolean maximized = gdk_surface_get_state (window) & GDK_SURFACE_STATE_MAXIMIZED;
-
- if (maximized)
- {
- lastMaximizedFrame = newFrame;
- gdk_synthesize_surface_state (window,
- GDK_SURFACE_STATE_MAXIMIZED,
- 0);
- }
- else
- {
- lastUnmaximizedFrame = [nsWindow frame];
- gdk_synthesize_surface_state (window,
- 0,
- GDK_SURFACE_STATE_MAXIMIZED);
- }
-
- inMaximizeTransition = YES;
- return YES;
-}
-
--(void)windowDidEndLiveResize:(NSNotification *)aNotification
-{
- inMaximizeTransition = NO;
-}
-
--(NSSize)window:(NSWindow *)window willUseFullScreenContentSize:(NSSize)proposedSize
-{
- return [[window screen] frame].size;
-}
-
--(void)windowWillEnterFullScreen:(NSNotification *)aNotification
-{
- lastUnfullscreenFrame = [self frame];
-}
-
--(void)windowWillExitFullScreen:(NSNotification *)aNotification
-{
- [self setFrame:lastUnfullscreenFrame display:YES];
-}
-
-@end
+++ /dev/null
-/* GdkQuartzNSWindow.h
- *
- * Copyright (C) 2005-2007 Imendio AB
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import <AppKit/AppKit.h>
-#import <Foundation/Foundation.h>
-#include <glib.h>
-#include <gdk.h>
-
-@interface GdkQuartzNSWindow : NSWindow {
- BOOL inMove;
- BOOL inShowOrHide;
- BOOL initialPositionKnown;
-
- /* Manually triggered move/resize (not by the window manager) */
- BOOL inManualMove;
- BOOL inManualResize;
- BOOL inTrackManualResize;
- NSPoint initialMoveLocation;
- NSPoint initialResizeLocation;
- NSRect initialResizeFrame;
- GdkSurfaceEdge resizeEdge;
-
- NSRect lastUnmaximizedFrame;
- NSRect lastMaximizedFrame;
- NSRect lastUnfullscreenFrame;
- BOOL inMaximizeTransition;
-}
-
--(BOOL)isInMove;
--(void)beginManualMove;
--(BOOL)trackManualMove;
--(BOOL)isInManualResizeOrMove;
--(void)beginManualResize:(GdkSurfaceEdge)edge;
--(BOOL)trackManualResize;
--(void)showAndMakeKey:(BOOL)makeKey;
--(void)hide;
-
-#ifdef AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
--(void)setStyleMask:(NSUInteger)styleMask;
-#endif
-
-@end
-
-
-
-
+++ /dev/null
-/* GdkQuartzView.m
- *
- * Copyright (C) 2005-2007 Imendio AB
- * Copyright (C) 2011 Hiroyuki Yamamoto
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-#import "GdkQuartzView.h"
-#include "gdkquartzsurface.h"
-#include "gdkprivate-quartz.h"
-#include "gdkquartz.h"
-
-@implementation GdkQuartzView
-
--(id)initWithFrame: (NSRect)frameRect
-{
- if ((self = [super initWithFrame: frameRect]))
- {
- markedRange = NSMakeRange (NSNotFound, 0);
- selectedRange = NSMakeRange (NSNotFound, 0);
- }
-
- return self;
-}
-
--(BOOL)acceptsFirstResponder
-{
- GDK_NOTE (EVENTS, g_message ("acceptsFirstResponder"));
- return YES;
-}
-
--(BOOL)becomeFirstResponder
-{
- GDK_NOTE (EVENTS, g_message ("becomeFirstResponder"));
- return YES;
-}
-
--(BOOL)resignFirstResponder
-{
- GDK_NOTE (EVENTS, g_message ("resignFirstResponder"));
- return YES;
-}
-
--(void) keyDown: (NSEvent *) theEvent
-{
- GDK_NOTE (EVENTS, g_message ("keyDown"));
- [self interpretKeyEvents: [NSArray arrayWithObject: theEvent]];
-}
-
--(void)flagsChanged: (NSEvent *) theEvent
-{
-}
-
--(NSUInteger)characterIndexForPoint: (NSPoint)aPoint
-{
- GDK_NOTE (EVENTS, g_message ("characterIndexForPoint"));
- return 0;
-}
-
--(NSRect)firstRectForCharacterRange: (NSRange)aRange actualRange: (NSRangePointer)actualRange
-{
- GDK_NOTE (EVENTS, g_message ("firstRectForCharacterRange"));
- gint ns_x, ns_y;
- GdkRectangle *rect;
-
- rect = g_object_get_data (G_OBJECT (gdk_surface), GIC_CURSOR_RECT);
- if (rect)
- {
- _gdk_quartz_surface_gdk_xy_to_xy (rect->x, rect->y + rect->height,
- &ns_x, &ns_y);
-
- return NSMakeRect (ns_x, ns_y, rect->width, rect->height);
- }
- else
- {
- return NSMakeRect (0, 0, 0, 0);
- }
-}
-
--(NSArray *)validAttributesForMarkedText
-{
- GDK_NOTE (EVENTS, g_message ("validAttributesForMarkedText"));
- return [NSArray arrayWithObjects: NSUnderlineStyleAttributeName, nil];
-}
-
--(NSAttributedString *)attributedSubstringForProposedRange: (NSRange)aRange actualRange: (NSRangePointer)actualRange
-{
- GDK_NOTE (EVENTS, g_message ("attributedSubstringForProposedRange"));
- return nil;
-}
-
--(BOOL)hasMarkedText
-{
- GDK_NOTE (EVENTS, g_message ("hasMarkedText"));
- return markedRange.location != NSNotFound && markedRange.length != 0;
-}
-
--(NSRange)markedRange
-{
- GDK_NOTE (EVENTS, g_message ("markedRange"));
- return markedRange;
-}
-
--(NSRange)selectedRange
-{
- GDK_NOTE (EVENTS, g_message ("selectedRange"));
- return selectedRange;
-}
-
--(void)unmarkText
-{
- GDK_NOTE (EVENTS, g_message ("unmarkText"));
- gchar *prev_str;
- markedRange = selectedRange = NSMakeRange (NSNotFound, 0);
-
- g_object_set_data_full (G_OBJECT (gdk_surface), TIC_MARKED_TEXT, NULL, g_free);
-}
-
--(void)setMarkedText: (id)aString selectedRange: (NSRange)newSelection replacementRange: (NSRange)replacementRange
-{
- GDK_NOTE (EVENTS, g_message ("setMarkedText"));
- const char *str;
- gchar *prev_str;
-
- if (replacementRange.location == NSNotFound)
- {
- markedRange = NSMakeRange (newSelection.location, [aString length]);
- selectedRange = NSMakeRange (newSelection.location, newSelection.length);
- }
- else {
- markedRange = NSMakeRange (replacementRange.location, [aString length]);
- selectedRange = NSMakeRange (replacementRange.location + newSelection.location, newSelection.length);
- }
-
- if ([aString isKindOfClass: [NSAttributedString class]])
- {
- str = [[aString string] UTF8String];
- }
- else {
- str = [aString UTF8String];
- }
-
- g_object_set_data_full (G_OBJECT (gdk_surface), TIC_MARKED_TEXT, g_strdup (str), g_free);
- g_object_set_data (G_OBJECT (gdk_surface), TIC_SELECTED_POS,
- GUINT_TO_POINTER (selectedRange.location));
- g_object_set_data (G_OBJECT (gdk_surface), TIC_SELECTED_LEN,
- GUINT_TO_POINTER (selectedRange.length));
-
- GDK_NOTE (EVENTS, g_message ("setMarkedText: set %s (%p, nsview %p): %s",
- TIC_MARKED_TEXT, gdk_surface, self,
- str ? str : "(empty)"));
-
- /* handle text input changes by mouse events */
- if (!GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (gdk_surface),
- TIC_IN_KEY_DOWN)))
- {
- _gdk_quartz_synthesize_null_key_event(gdk_surface);
- }
-}
-
--(void)doCommandBySelector: (SEL)aSelector
-{
- GDK_NOTE (EVENTS, g_message ("doCommandBySelector"));
- if ([self respondsToSelector: aSelector])
- [self performSelector: aSelector];
-}
-
--(void)insertText: (id)aString replacementRange: (NSRange)replacementRange
-{
- GDK_NOTE (EVENTS, g_message ("insertText"));
- const char *str;
- NSString *string;
- gchar *prev_str;
-
- if ([self hasMarkedText])
- [self unmarkText];
-
- if ([aString isKindOfClass: [NSAttributedString class]])
- string = [aString string];
- else
- string = aString;
-
- NSCharacterSet *ctrlChars = [NSCharacterSet controlCharacterSet];
- NSCharacterSet *wsnlChars = [NSCharacterSet whitespaceAndNewlineCharacterSet];
- if ([string rangeOfCharacterFromSet:ctrlChars].length &&
- [string rangeOfCharacterFromSet:wsnlChars].length == 0)
- {
- /* discard invalid text input with Chinese input methods */
- str = "";
- [self unmarkText];
- NSInputManager *currentInputManager = [NSInputManager currentInputManager];
- [currentInputManager markedTextAbandoned:self];
- }
- else
- {
- str = [string UTF8String];
- }
-
- g_object_set_data_full (G_OBJECT (gdk_surface), TIC_INSERT_TEXT, g_strdup (str), g_free);
- GDK_NOTE (EVENTS, g_message ("insertText: set %s (%p, nsview %p): %s",
- TIC_INSERT_TEXT, gdk_surface, self,
- str ? str : "(empty)"));
-
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_FILTERED));
-
- /* handle text input changes by mouse events */
- if (!GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (gdk_surface),
- TIC_IN_KEY_DOWN)))
- {
- _gdk_quartz_synthesize_null_key_event(gdk_surface);
- }
-}
-
--(void)deleteBackward: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("deleteBackward"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)deleteForward: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("deleteForward"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)deleteToBeginningOfLine: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("deleteToBeginningOfLine"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)deleteToEndOfLine: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("deleteToEndOfLine"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)deleteWordBackward: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("deleteWordBackward"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)deleteWordForward: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("deleteWordForward"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)insertBacktab: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("insertBacktab"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)insertNewline: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("insertNewline"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY, GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)insertTab: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("insertTab"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)moveBackward: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("moveBackward"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)moveBackwardAndModifySelection: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("moveBackwardAndModifySelection"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)moveDown: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("moveDown"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)moveDownAndModifySelection: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("moveDownAndModifySelection"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)moveForward: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("moveForward"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)moveForwardAndModifySelection: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("moveForwardAndModifySelection"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)moveLeft: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("moveLeft"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)moveLeftAndModifySelection: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("moveLeftAndModifySelection"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)moveRight: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("moveRight"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)moveRightAndModifySelection: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("moveRightAndModifySelection"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)moveToBeginningOfDocument: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("moveToBeginningOfDocument"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)moveToBeginningOfDocumentAndModifySelection: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("moveToBeginningOfDocumentAndModifySelection"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)moveToBeginningOfLine: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("moveToBeginningOfLine"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)moveToBeginningOfLineAndModifySelection: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("moveToBeginningOfLineAndModifySelection"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)moveToEndOfDocument: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("moveToEndOfDocument"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)moveToEndOfDocumentAndModifySelection: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("moveToEndOfDocumentAndModifySelection"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)moveToEndOfLine: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("moveToEndOfLine"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)moveToEndOfLineAndModifySelection: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("moveToEndOfLineAndModifySelection"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)moveUp: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("moveUp"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)moveUpAndModifySelection: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("moveUpAndModifySelection"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)moveWordBackward: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("moveWordBackward"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)moveWordBackwardAndModifySelection: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("moveWordBackwardAndModifySelection"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)moveWordForward: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("moveWordForward"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)moveWordForwardAndModifySelection: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("moveWordForwardAndModifySelection"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)moveWordLeft: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("moveWordLeft"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)moveWordLeftAndModifySelection: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("moveWordLeftAndModifySelection"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)moveWordRight: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("moveWordRight"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)moveWordRightAndModifySelection: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("moveWordRightAndModifySelection"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)pageDown: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("pageDown"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)pageDownAndModifySelection: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("pageDownAndModifySelection"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)pageUp: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("pageUp"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)pageUpAndModifySelection: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("pageUpAndModifySelection"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)selectAll: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("selectAll"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)selectLine: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("selectLine"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)selectWord: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("selectWord"));
- g_object_set_data (G_OBJECT (gdk_surface), GIC_FILTER_KEY,
- GUINT_TO_POINTER (GIC_FILTER_PASSTHRU));
-}
-
--(void)noop: (id)sender
-{
- GDK_NOTE (EVENTS, g_message ("noop"));
-}
-
-/* --------------------------------------------------------------- */
-
--(void)dealloc
-{
- if (trackingRect)
- {
- [self removeTrackingRect: trackingRect];
- trackingRect = 0;
- }
-
- [super dealloc];
-}
-
--(void)setGdkSurface: (GdkSurface *)window
-{
- gdk_surface = window;
-}
-
--(GdkSurface *)gdkSurface
-{
- return gdk_surface;
-}
-
--(NSTrackingRectTag)trackingRect
-{
- return trackingRect;
-}
-
--(BOOL)isFlipped
-{
- return YES;
-}
-
--(BOOL)isOpaque
-{
- if (GDK_SURFACE_DESTROYED (gdk_surface))
- return YES;
-
- return NO;
-}
-
--(void)drawRect: (NSRect)rect
-{
- GdkRectangle gdk_rect;
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (gdk_window->impl);
- const NSRect *drawn_rects;
- NSInteger count;
- int i;
- cairo_region_t *region;
-
- if (GDK_SURFACE_DESTROYED (gdk_surface))
- return;
-
- if (! (gdk_window->event_mask & GDK_EXPOSURE_MASK))
- return;
-
- if (NSEqualRects (rect, NSZeroRect))
- return;
-
- if (!GDK_SURFACE_IS_MAPPED (gdk_surface))
- {
- /* If the window is not yet mapped, clip_region_with_children
- * will be empty causing the usual code below to draw nothing.
- * To not see garbage on the screen, we draw an aesthetic color
- * here. The garbage would be visible if any widget enabled
- * the NSView's CALayer in order to add sublayers for custom
- * native rendering.
- */
- [NSGraphicsContext saveGraphicsState];
-
- [[NSColor windowBackgroundColor] setFill];
- [NSBezierPath fillRect: rect];
-
- [NSGraphicsContext restoreGraphicsState];
-
- return;
- }
-
- /* Clear our own bookkeeping of regions that need display */
- if (impl->needs_display_region)
- {
- cairo_region_destroy (impl->needs_display_region);
- impl->needs_display_region = NULL;
- }
-
- [self getRectsBeingDrawn: &drawn_rects count: &count];
- region = cairo_region_create ();
-
- for (i = 0; i < count; i++)
- {
- gdk_rect.x = drawn_rects[i].origin.x;
- gdk_rect.y = drawn_rects[i].origin.y;
- gdk_rect.width = drawn_rects[i].size.width;
- gdk_rect.height = drawn_rects[i].size.height;
-
- cairo_region_union_rectangle (region, &gdk_rect);
- }
-
- impl->in_paint_rect_count++;
- _gdk_surface_process_updates_recurse (gdk_surface, region);
- impl->in_paint_rect_count--;
-
- cairo_region_destroy (region);
-
- if (needsInvalidateShadow)
- {
- [[self window] invalidateShadow];
- needsInvalidateShadow = NO;
- }
-}
-
--(void)setNeedsInvalidateShadow: (BOOL)invalidate
-{
- needsInvalidateShadow = invalidate;
-}
-
-/* For information on setting up tracking rects properly, see here:
- * http://developer.apple.com/documentation/Cocoa/Conceptual/EventOverview/EventOverview.pdf
- */
--(void)updateTrackingRect
-{
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (gdk_window->impl);
- NSRect rect;
-
- if (!impl || !impl->toplevel)
- return;
-
- if (trackingRect)
- {
- [self removeTrackingRect: trackingRect];
- trackingRect = 0;
- }
-
- if (!impl->toplevel)
- return;
-
- /* Note, if we want to set assumeInside we can use:
- * NSPointInRect ([[self window] convertScreenToBase:[NSEvent mouseLocation]], rect)
- */
-
- rect = [self bounds];
- trackingRect = [self addTrackingRect: rect
- owner: self
- userData: nil
- assumeInside: NO];
-}
-
--(void)viewDidMoveToWindow
-{
- if (![self window]) /* We are destroyed already */
- return;
-
- [self updateTrackingRect];
-}
-
--(void)viewWillMoveToWindow: (NSWindow *)newWindow
-{
- if (newWindow == nil && trackingRect)
- {
- [self removeTrackingRect: trackingRect];
- trackingRect = 0;
- }
-}
-
--(void)setFrame: (NSRect)frame
-{
- [super setFrame: frame];
-
- if ([self window])
- [self updateTrackingRect];
-}
-
-@end
+++ /dev/null
-/* GdkQuartzView.h
- *
- * Copyright (C) 2005 Imendio AB
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#import <AppKit/AppKit.h>
-#include "gdk/gdk.h"
-
-/* Text Input Client */
-#define TIC_MARKED_TEXT "tic-marked-text"
-#define TIC_SELECTED_POS "tic-selected-pos"
-#define TIC_SELECTED_LEN "tic-selected-len"
-#define TIC_INSERT_TEXT "tic-insert-text"
-#define TIC_IN_KEY_DOWN "tic-in-key-down"
-
-/* GtkIMContext */
-#define GIC_CURSOR_RECT "gic-cursor-rect"
-#define GIC_FILTER_KEY "gic-filter-key"
-#define GIC_FILTER_PASSTHRU 0
-#define GIC_FILTER_FILTERED 1
-
-@interface GdkQuartzView : NSView <NSTextInputClient>
-{
- GdkSurface *gdk_surface;
- NSTrackingRectTag trackingRect;
- BOOL needsInvalidateShadow;
- NSRange markedRange;
- NSRange selectedRange;
-}
-
-- (void)setGdkSurface: (GdkSurface *)window;
-- (GdkSurface *)gdkSurface;
-- (NSTrackingRectTag)trackingRect;
-- (void)setNeedsInvalidateShadow: (BOOL)invalidate;
-
-@end
+++ /dev/null
-/* GDK - The GIMP Drawing Kit
- *
- * Copyright © 2018 Benjamin Otte
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-
-#include "gdkconfig.h"
-
-#include "gdkcairocontext-quartz.h"
-
-G_DEFINE_TYPE (GdkQuartzCairoContext, gdk_quartz_cairo_context, GDK_TYPE_CAIRO_CONTEXT)
-
-static void
-gdk_quartz_cairo_context_class_init (GdkQuartzCairoContextClass *klass)
-{
-}
-
-static void
-gdk_quartz_cairo_context_init (GdkQuartzCairoContext *self)
-{
-}
-
+++ /dev/null
-/* GDK - The GIMP Drawing Kit
- *
- * Copyright © 2018 Benjamin Otte
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __GDK_QUARTZ_CAIRO_CONTEXT__
-#define __GDK_QUARTZ_CAIRO_CONTEXT__
-
-#include "gdkconfig.h"
-
-#include "gdkcairocontextprivate.h"
-
-G_BEGIN_DECLS
-
-#define GDK_TYPE_QUARTZ_CAIRO_CONTEXT (gdk_quartz_cairo_context_get_type ())
-#define GDK_QUARTZ_CAIRO_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_QUARTZ_CAIRO_CONTEXT, GdkQuartzCairoContext))
-#define GDK_IS_QUARTZ_CAIRO_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_QUARTZ_CAIRO_CONTEXT))
-#define GDK_QUARTZ_CAIRO_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_QUARTZ_CAIRO_CONTEXT, GdkQuartzCairoContextClass))
-#define GDK_IS_QUARTZ_CAIRO_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_QUARTZ_CAIRO_CONTEXT))
-#define GDK_QUARTZ_CAIRO_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_QUARTZ_CAIRO_CONTEXT, GdkQuartzCairoContextClass))
-
-typedef struct _GdkQuartzCairoContext GdkQuartzCairoContext;
-typedef struct _GdkQuartzCairoContextClass GdkQuartzCairoContextClass;
-
-struct _GdkQuartzCairoContext
-{
- GdkCairoContext parent_instance;
-};
-
-struct _GdkQuartzCairoContextClass
-{
- GdkCairoContextClass parent_class;
-};
-
-GDK_AVAILABLE_IN_ALL
-GType gdk_quartz_cairo_context_get_type (void) G_GNUC_CONST;
-
-G_END_DECLS
-
-#endif /* __GDK_QUARTZ_CAIRO_CONTEXT__ */
+++ /dev/null
-/* gdkcursor-quartz.c
- *
- * Copyright (C) 2005-2007 Imendio AB
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-
-#include "gdkdisplay.h"
-#include "gdkcursor.h"
-#include "gdkcursorprivate.h"
-#include "gdkquartzcursor.h"
-#include "gdkprivate-quartz.h"
-
-#include "xcursors.h"
-
-struct _GdkQuartzCursor
-{
- GdkCursor cursor;
-
- NSCursor *nscursor;
-};
-
-struct _GdkQuartzCursorClass
-{
- GdkCursorClass cursor_class;
-};
-
-
-static GdkCursor *cached_xcursors[G_N_ELEMENTS (xcursors)];
-
-static GdkCursor *
-gdk_quartz_cursor_new_from_nscursor (NSCursor *nscursor,
- GdkCursorType cursor_type)
-{
- GdkQuartzCursor *private;
-
- private = g_object_new (GDK_TYPE_QUARTZ_CURSOR,
- "cursor-type", cursor_type,
- "display", _gdk_display,
- NULL);
- private->nscursor = nscursor;
-
- return GDK_CURSOR (private);
-}
-
-static GdkCursor *
-create_blank_cursor (void)
-{
- NSCursor *nscursor;
- NSImage *nsimage;
- NSSize size = { 1.0, 1.0 };
-
- nsimage = [[NSImage alloc] initWithSize:size];
- nscursor = [[NSCursor alloc] initWithImage:nsimage
- hotSpot:NSMakePoint(0.0, 0.0)];
- [nsimage release];
-
- return gdk_quartz_cursor_new_from_nscursor (nscursor, GDK_BLANK_CURSOR);
-}
-
-static gboolean
-get_bit (const guchar *data,
- gint width,
- gint height,
- gint x,
- gint y)
-{
- gint bytes_per_line;
- const guchar *src;
-
- if (x < 0 || y < 0 || x >= width || y >= height)
- return FALSE;
-
- bytes_per_line = (width + 7) / 8;
-
- src = &data[y * bytes_per_line];
- return ((src[x / 8] >> x % 8) & 1);
-}
-
-static GdkCursor *
-create_builtin_cursor (GdkCursorType cursor_type)
-{
- GdkCursor *cursor;
- NSBitmapImageRep *bitmap_rep;
- NSInteger mask_width, mask_height;
- gint src_width, src_height;
- gint dst_stride;
- const guchar *mask_start, *src_start;
- gint dx, dy;
- gint x, y;
- NSPoint hotspot;
- NSImage *image;
- NSCursor *nscursor;
-
- if (cursor_type >= G_N_ELEMENTS (xcursors) || cursor_type < 0)
- return NULL;
-
- cursor = cached_xcursors[cursor_type];
- if (cursor)
- return cursor;
-
- GDK_QUARTZ_ALLOC_POOL;
-
- src_width = xcursors[cursor_type].width;
- src_height = xcursors[cursor_type].height;
- mask_width = xcursors[cursor_type+1].width;
- mask_height = xcursors[cursor_type+1].height;
-
- bitmap_rep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
- pixelsWide:mask_width pixelsHigh:mask_height
- bitsPerSample:8 samplesPerPixel:4
- hasAlpha:YES isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace
- bytesPerRow:0 bitsPerPixel:0];
-
- dst_stride = [bitmap_rep bytesPerRow];
-
- src_start = xcursors[cursor_type].bits;
- mask_start = xcursors[cursor_type+1].bits;
-
- dx = xcursors[cursor_type+1].hotx - xcursors[cursor_type].hotx;
- dy = xcursors[cursor_type+1].hoty - xcursors[cursor_type].hoty;
-
- for (y = 0; y < mask_height; y++)
- {
- guchar *dst = [bitmap_rep bitmapData] + y * dst_stride;
-
- for (x = 0; x < mask_width; x++)
- {
- if (get_bit (mask_start, mask_width, mask_height, x, y))
- {
- if (get_bit (src_start, src_width, src_height, x - dx, y - dy))
- {
- *dst++ = 0;
- *dst++ = 0;
- *dst++ = 0;
- }
- else
- {
- *dst++ = 0xff;
- *dst++ = 0xff;
- *dst++ = 0xff;
- }
-
- *dst++ = 0xff;
- }
- else
- {
- *dst++ = 0;
- *dst++ = 0;
- *dst++ = 0;
- *dst++ = 0;
- }
- }
- }
-
- image = [[NSImage alloc] init];
- [image addRepresentation:bitmap_rep];
- [bitmap_rep release];
-
- hotspot = NSMakePoint (xcursors[cursor_type+1].hotx,
- xcursors[cursor_type+1].hoty);
-
- nscursor = [[NSCursor alloc] initWithImage:image hotSpot:hotspot];
- [image release];
-
- cursor = gdk_quartz_cursor_new_from_nscursor (nscursor, GDK_CURSOR_IS_PIXMAP);
-
- cached_xcursors[cursor_type] = g_object_ref (cursor);
-
- GDK_QUARTZ_RELEASE_POOL;
-
- return cursor;
-}
-
-GdkCursor*
-_gdk_quartz_display_get_cursor_for_type (GdkDisplay *display,
- GdkCursorType cursor_type)
-{
- NSCursor *nscursor;
-
- g_return_val_if_fail (display == gdk_display_get_default (), NULL);
-
- switch (cursor_type)
- {
- case GDK_XTERM:
- nscursor = [NSCursor IBeamCursor];
- break;
- case GDK_SB_H_DOUBLE_ARROW:
- nscursor = [NSCursor resizeLeftRightCursor];
- break;
- case GDK_SB_V_DOUBLE_ARROW:
- nscursor = [NSCursor resizeUpDownCursor];
- break;
- case GDK_SB_UP_ARROW:
- case GDK_BASED_ARROW_UP:
- case GDK_BOTTOM_TEE:
- case GDK_TOP_SIDE:
- nscursor = [NSCursor resizeUpCursor];
- break;
- case GDK_SB_DOWN_ARROW:
- case GDK_BASED_ARROW_DOWN:
- case GDK_TOP_TEE:
- case GDK_BOTTOM_SIDE:
- nscursor = [NSCursor resizeDownCursor];
- break;
- case GDK_SB_LEFT_ARROW:
- case GDK_RIGHT_TEE:
- case GDK_LEFT_SIDE:
- nscursor = [NSCursor resizeLeftCursor];
- break;
- case GDK_SB_RIGHT_ARROW:
- case GDK_LEFT_TEE:
- case GDK_RIGHT_SIDE:
- nscursor = [NSCursor resizeRightCursor];
- break;
- case GDK_TCROSS:
- case GDK_CROSS:
- case GDK_CROSSHAIR:
- case GDK_DIAMOND_CROSS:
- nscursor = [NSCursor crosshairCursor];
- break;
- case GDK_HAND1:
- case GDK_HAND2:
- nscursor = [NSCursor pointingHandCursor];
- break;
- case GDK_CURSOR_IS_PIXMAP:
- return NULL;
- case GDK_BLANK_CURSOR:
- return create_blank_cursor ();
- default:
- return g_object_ref (create_builtin_cursor (cursor_type));
- }
-
- [nscursor retain];
- return gdk_quartz_cursor_new_from_nscursor (nscursor, cursor_type);
-}
-
-
-GdkCursor *
-_gdk_quartz_display_get_cursor_for_surface (GdkDisplay *display,
- cairo_surface_t *surface,
- gdouble x,
- gdouble y)
-{
- NSImage *image;
- NSCursor *nscursor;
- GdkCursor *cursor;
- GdkPixbuf *pixbuf;
-
- GDK_QUARTZ_ALLOC_POOL;
-
- pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0,
- cairo_image_surface_get_width (surface),
- cairo_image_surface_get_height (surface));
- image = gdk_quartz_pixbuf_to_ns_image_libgtk_only (pixbuf);
- nscursor = [[NSCursor alloc] initWithImage:image hotSpot:NSMakePoint(x, y)];
-
- cursor = gdk_quartz_cursor_new_from_nscursor (nscursor, GDK_CURSOR_IS_PIXMAP);
-
- g_object_unref (pixbuf);
-
- GDK_QUARTZ_RELEASE_POOL;
-
- return cursor;
-}
-
-/* OS X only exports a number of cursor types in its public NSCursor interface.
- * By overriding the private _coreCursorType method, we can tell OS X to load
- * one of its internal cursors instead (since cursor images are loaded on demand
- * instead of in advance). WebKit does this too.
- */
-
-@interface gdkCoreCursor : NSCursor {
-@private
- int type;
- BOOL override;
-}
-@end
-
-@implementation gdkCoreCursor
-
-- (int)_coreCursorType
-{
- if (self->override)
- return self->type;
- return [super _coreCursorType];
-}
-
-#define CUSTOM_CURSOR_CTOR(name, id) \
- + (gdkCoreCursor *)name \
- { \
- gdkCoreCursor *obj; \
- obj = [self new]; \
- if (obj) { \
- obj->override = YES; \
- obj->type = id; \
- } \
- return obj; \
- }
-CUSTOM_CURSOR_CTOR(gdkHelpCursor, 40)
-CUSTOM_CURSOR_CTOR(gdkProgressCursor, 4)
-/* TODO OS X doesn't seem to have a way to get this. There is an undocumented
- * method +[NSCursor _waitCursor], but it doesn't actually return this cursor,
- * but rather some odd low-quality non-animating version of this cursor. Use
- * the progress cursor instead for now.
- */
-CUSTOM_CURSOR_CTOR(gdkWaitCursor, 4)
-CUSTOM_CURSOR_CTOR(gdkAliasCursor, 2)
-CUSTOM_CURSOR_CTOR(gdkMoveCursor, 39)
-/* TODO OS X doesn't seem to provide one; copy the move cursor for now
- * since it looks similar to what we want. */
-CUSTOM_CURSOR_CTOR(gdkAllScrollCursor, 39)
-CUSTOM_CURSOR_CTOR(gdkNEResizeCursor, 29)
-CUSTOM_CURSOR_CTOR(gdkNWResizeCursor, 33)
-CUSTOM_CURSOR_CTOR(gdkSEResizeCursor, 35)
-CUSTOM_CURSOR_CTOR(gdkSWResizeCursor, 37)
-CUSTOM_CURSOR_CTOR(gdkEWResizeCursor, 28)
-CUSTOM_CURSOR_CTOR(gdkNSResizeCursor, 32)
-CUSTOM_CURSOR_CTOR(gdkNESWResizeCursor, 30)
-CUSTOM_CURSOR_CTOR(gdkNWSEResizeCursor, 34)
-CUSTOM_CURSOR_CTOR(gdkZoomInCursor, 42)
-CUSTOM_CURSOR_CTOR(gdkZoomOutCursor, 43)
-
-@end
-
-struct CursorsByName {
- const gchar *name;
- NSString *selector;
-};
-
-static const struct CursorsByName cursors_by_name[] = {
- /* Link & Status */
- { "context-menu", @"contextualMenuCursor" },
- { "help", @"gdkHelpCursor" },
- { "pointer", @"pointingHandCursor" },
- { "progress", @"gdkProgressCursor" },
- { "wait", @"gdkWaitCursor" },
- /* Selection */
- { "cell", @"crosshairCursor" },
- { "crosshair", @"crosshairCursor" },
- { "text", @"IBeamCursor" },
- { "vertical-text", @"IBeamCursorForVerticalLayout" },
- /* Drag & Drop */
- { "alias", @"gdkAliasCursor" },
- { "copy", @"dragCopyCursor" },
- { "move", @"gdkMoveCursor" },
- { "no-drop", @"operationNotAllowedCursor" },
- { "not-allowed", @"operationNotAllowedCursor" },
- { "grab", @"openHandCursor" },
- { "grabbing", @"closedHandCursor" },
- /* Resize & Scrolling */
- { "all-scroll", @"gdkAllScrollCursor" },
- { "col-resize", @"resizeLeftRightCursor" },
- { "row-resize", @"resizeUpDownCursor" },
- { "n-resize", @"resizeUpCursor" },
- { "e-resize", @"resizeRightCursor" },
- { "s-resize", @"resizeDownCursor" },
- { "w-resize", @"resizeLeftCursor" },
- { "ne-resize", @"gdkNEResizeCursor" },
- { "nw-resize", @"gdkNWResizeCursor" },
- { "se-resize", @"gdkSEResizeCursor" },
- { "sw-resize", @"gdkSWResizeCursor" },
- { "ew-resize", @"gdkEWResizeCursor" },
- { "ns-resize", @"gdkNSResizeCursor" },
- { "nesw-resize", @"gdkNESWResizeCursor" },
- { "nwse-resize", @"gdkNWSEResizeCursor" },
- /* Zoom */
- { "zoom-in", @"gdkZoomInCursor" },
- { "zoom-out", @"gdkZoomOutCursor" },
- { NULL, NULL },
-};
-
-GdkCursor*
-_gdk_quartz_display_get_cursor_for_name (GdkDisplay *display,
- const gchar *name)
-{
- NSCursor *nscursor;
- const struct CursorsByName *test;
- SEL selector;
-
- if (name == NULL || g_str_equal (name, "none"))
- return create_blank_cursor ();
-
- // use this selector if nothing found
- selector = @selector(arrowCursor);
- for (test = cursors_by_name; test->name != NULL; test++)
- if (g_str_equal (name, test->name))
- {
- selector = NSSelectorFromString(test->selector);
- break;
- }
- nscursor = [[gdkCoreCursor class] performSelector:selector];
-
- [nscursor retain];
- return gdk_quartz_cursor_new_from_nscursor (nscursor, GDK_CURSOR_IS_PIXMAP);
-}
-
-G_DEFINE_TYPE (GdkQuartzCursor, gdk_quartz_cursor, GDK_TYPE_CURSOR)
-
-static void
-gdk_quartz_cursor_finalize (GObject *object)
-{
- GdkQuartzCursor *private = GDK_QUARTZ_CURSOR (object);
-
- if (private->nscursor)
- [private->nscursor release];
- private->nscursor = NULL;
-}
-
-static void
-gdk_quartz_cursor_class_init (GdkQuartzCursorClass *quartz_cursor_class)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (quartz_cursor_class);
-
- object_class->finalize = gdk_quartz_cursor_finalize;
-}
-
-static void
-gdk_quartz_cursor_init (GdkQuartzCursor *cursor)
-{
-}
-
-
-gboolean
-_gdk_quartz_display_supports_cursor_alpha (GdkDisplay *display)
-{
- return TRUE;
-}
-
-gboolean
-_gdk_quartz_display_supports_cursor_color (GdkDisplay *display)
-{
- return TRUE;
-}
-
-void
-_gdk_quartz_display_get_default_cursor_size (GdkDisplay *display,
- guint *width,
- guint *height)
-{
- /* Mac OS X doesn't have the notion of a default size */
- *width = 32;
- *height = 32;
-}
-
-void
-_gdk_quartz_display_get_maximal_cursor_size (GdkDisplay *display,
- guint *width,
- guint *height)
-{
- /* Cursor sizes in Mac OS X can be arbitrarily large */
- *width = 65536;
- *height = 65536;
-}
-
-NSCursor *
-_gdk_quartz_cursor_get_ns_cursor (GdkCursor *cursor)
-{
- GdkQuartzCursor *cursor_private;
-
- if (!cursor)
- return [NSCursor arrowCursor];
-
- g_return_val_if_fail (GDK_IS_QUARTZ_CURSOR (cursor), NULL);
-
- cursor_private = GDK_QUARTZ_CURSOR (cursor);
-
- return cursor_private->nscursor;
-}
+++ /dev/null
-/* GDK - The GIMP Drawing Kit
- * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
- * Copyright (C) 2010 Kristian Rietveld <kris@gtk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-
-#include <gdk/gdkdeviceprivate.h>
-#include <gdk/gdkdisplayprivate.h>
-
-#import "GdkQuartzView.h"
-#include "gdkquartzsurface.h"
-#include "gdkquartzcursor.h"
-#include "gdkprivate-quartz.h"
-#include "gdkquartzdevice-core.h"
-
-struct _GdkQuartzDeviceCore
-{
- GdkDevice parent_instance;
-};
-
-struct _GdkQuartzDeviceCoreClass
-{
- GdkDeviceClass parent_class;
-};
-
-static gboolean gdk_quartz_device_core_get_history (GdkDevice *device,
- GdkSurface *window,
- guint32 start,
- guint32 stop,
- GdkTimeCoord ***events,
- gint *n_events);
-static void gdk_quartz_device_core_get_state (GdkDevice *device,
- GdkSurface *window,
- gdouble *axes,
- GdkModifierType *mask);
-static void gdk_quartz_device_core_set_surface_cursor (GdkDevice *device,
- GdkSurface *window,
- GdkCursor *cursor);
-static void gdk_quartz_device_core_warp (GdkDevice *device,
- gdouble x,
- gdouble y);
-static void gdk_quartz_device_core_query_state (GdkDevice *device,
- GdkSurface *window,
- GdkSurface **root_window,
- GdkSurface **child_window,
- gdouble *root_x,
- gdouble *root_y,
- gdouble *win_x,
- gdouble *win_y,
- GdkModifierType *mask);
-static GdkGrabStatus gdk_quartz_device_core_grab (GdkDevice *device,
- GdkSurface *window,
- gboolean owner_events,
- GdkEventMask event_mask,
- GdkSurface *confine_to,
- GdkCursor *cursor,
- guint32 time_);
-static void gdk_quartz_device_core_ungrab (GdkDevice *device,
- guint32 time_);
-static GdkSurface * gdk_quartz_device_core_surface_at_position (GdkDevice *device,
- gdouble *win_x,
- gdouble *win_y,
- GdkModifierType *mask,
- gboolean get_toplevel);
-
-
-G_DEFINE_TYPE (GdkQuartzDeviceCore, gdk_quartz_device_core, GDK_TYPE_DEVICE)
-
-static void
-gdk_quartz_device_core_class_init (GdkQuartzDeviceCoreClass *klass)
-{
- GdkDeviceClass *device_class = GDK_DEVICE_CLASS (klass);
-
- device_class->get_history = gdk_quartz_device_core_get_history;
- device_class->get_state = gdk_quartz_device_core_get_state;
- device_class->set_surface_cursor = gdk_quartz_device_core_set_surface_cursor;
- device_class->warp = gdk_quartz_device_core_warp;
- device_class->query_state = gdk_quartz_device_core_query_state;
- device_class->grab = gdk_quartz_device_core_grab;
- device_class->ungrab = gdk_quartz_device_core_ungrab;
- device_class->surface_at_position = gdk_quartz_device_core_surface_at_position;
-}
-
-static void
-gdk_quartz_device_core_init (GdkQuartzDeviceCore *quartz_device_core)
-{
- GdkDevice *device;
-
- device = GDK_DEVICE (quartz_device_core);
-
- _gdk_device_add_axis (device, NULL, GDK_AXIS_X, 0, 0, 1);
- _gdk_device_add_axis (device, NULL, GDK_AXIS_Y, 0, 0, 1);
-}
-
-static gboolean
-gdk_quartz_device_core_get_history (GdkDevice *device,
- GdkSurface *window,
- guint32 start,
- guint32 stop,
- GdkTimeCoord ***events,
- gint *n_events)
-{
- return FALSE;
-}
-
-static void
-gdk_quartz_device_core_get_state (GdkDevice *device,
- GdkSurface *window,
- gdouble *axes,
- GdkModifierType *mask)
-{
- gdouble x_pos, y_pos;
-
- gdk_surface_get_device_position (window, device, &x_pos, &y_pos, mask);
-
- if (axes)
- {
- axes[0] = x_pos;
- axes[1] = y_pos;
- }
-}
-
-static void
-translate_coords_to_child_coords (GdkSurface *parent,
- GdkSurface *child,
- gint *x,
- gint *y)
-{
- GdkSurface *current = child;
-
- if (child == parent)
- return;
-
- while (current != parent)
- {
- gint tmp_x, tmp_y;
-
- gdk_surface_get_origin (current, &tmp_x, &tmp_y);
-
- *x -= tmp_x;
- *y -= tmp_y;
-
- current = gdk_surface_get_parent (current);
- }
-}
-
-static void
-gdk_quartz_device_core_set_surface_cursor (GdkDevice *device,
- GdkSurface *window,
- GdkCursor *cursor)
-{
- NSCursor *nscursor;
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- nscursor = _gdk_quartz_cursor_get_ns_cursor (cursor);
-
- [nscursor set];
-}
-
-static void
-gdk_quartz_device_core_warp (GdkDevice *device,
- gdouble x,
- gdouble y)
-{
- CGDisplayMoveCursorToPoint (CGMainDisplayID (), CGPointMake (x, y));
-}
-
-static GdkSurface *
-gdk_quartz_device_core_query_state_helper (GdkSurface *window,
- GdkDevice *device,
- gdouble *x,
- gdouble *y,
- GdkModifierType *mask)
-{
- GdkSurface *toplevel;
- NSPoint point;
- gint x_tmp, y_tmp;
- GdkSurface *found_window;
-
- g_return_val_if_fail (window == NULL || GDK_IS_SURFACE (window), NULL);
-
- if (GDK_SURFACE_DESTROYED (window))
- {
- *x = 0;
- *y = 0;
- *mask = 0;
- return NULL;
- }
-
- toplevel = gdk_surface_get_toplevel (window);
-
- if (mask)
- *mask = _gdk_quartz_events_get_current_keyboard_modifiers () |
- _gdk_quartz_events_get_current_mouse_modifiers ();
-
- /* Get the y coordinate, needs to be flipped. */
- if (window == _gdk_root)
- {
- point = [NSEvent mouseLocation];
- _gdk_quartz_surface_nspoint_to_gdk_xy (point, &x_tmp, &y_tmp);
- }
- else
- {
- GdkSurfaceImplQuartz *impl;
- NSWindow *nswindow;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (toplevel->impl);
- nswindow = impl->toplevel;
-
- point = [nswindow mouseLocationOutsideOfEventStream];
-
- x_tmp = point.x;
- y_tmp = toplevel->height - point.y;
-
- window = toplevel;
- }
-
- found_window = _gdk_quartz_surface_find_child (window, x_tmp, y_tmp,
- FALSE);
-
- if (found_window == _gdk_root)
- found_window = NULL;
- else if (found_window)
- translate_coords_to_child_coords (window, found_window,
- &x_tmp, &y_tmp);
-
- if (x)
- *x = x_tmp;
-
- if (y)
- *y = y_tmp;
-
- return found_window;
-}
-
-static void
-gdk_quartz_device_core_query_state (GdkDevice *device,
- GdkSurface *window,
- GdkSurface **child_window,
- gdouble *root_x,
- gdouble *root_y,
- gdouble *win_x,
- gdouble *win_y,
- GdkModifierType *mask)
-{
- GdkSurface *found_window;
- NSPoint point;
- gint x_tmp, y_tmp;
-
- if (window == NULL)
- window = _gdk_root;
-
- found_window = gdk_quartz_device_core_query_state_helper (window, device,
- win_x, win_y,
- mask);
-
- if (root_window)
- *root_window = _gdk_root;
-
- if (child_window)
- *child_window = found_window;
-
- point = [NSEvent mouseLocation];
- _gdk_quartz_surface_nspoint_to_gdk_xy (point, &x_tmp, &y_tmp);
-
- if (root_x)
- *root_x = x_tmp;
-
- if (root_y)
- *root_y = y_tmp;
-}
-
-static GdkGrabStatus
-gdk_quartz_device_core_grab (GdkDevice *device,
- GdkSurface *window,
- gboolean owner_events,
- GdkEventMask event_mask,
- GdkSurface *confine_to,
- GdkCursor *cursor,
- guint32 time_)
-{
- /* Should remain empty */
- return GDK_GRAB_SUCCESS;
-}
-
-static void
-gdk_quartz_device_core_ungrab (GdkDevice *device,
- guint32 time_)
-{
- GdkDeviceGrabInfo *grab;
-
- grab = _gdk_display_get_last_device_grab (_gdk_display, device);
- if (grab)
- grab->serial_end = 0;
-
- _gdk_display_device_grab_update (_gdk_display, device, NULL, 0);
-}
-
-static GdkSurface *
-gdk_quartz_device_core_surface_at_position (GdkDevice *device,
- gdouble *win_x,
- gdouble *win_y,
- GdkModifierType *mask,
- gboolean get_toplevel)
-{
- GdkSurface *found_window;
- NSPoint point;
- gint x_tmp, y_tmp;
-
- /* Get mouse coordinates, find window under the mouse pointer */
- point = [NSEvent mouseLocation];
- _gdk_quartz_surface_nspoint_to_gdk_xy (point, &x_tmp, &y_tmp);
-
- found_window = _gdk_quartz_surface_find_child (_gdk_root, x_tmp, y_tmp, get_toplevel);
-
- if (found_window)
- translate_coords_to_child_coords (_gdk_root, found_window, &x_tmp, &y_tmp);
-
- if (win_x)
- *win_x = found_window ? x_tmp : -1;
-
- if (win_y)
- *win_y = found_window ? y_tmp : -1;
-
- if (mask)
- *mask = _gdk_quartz_events_get_current_keyboard_modifiers () |
- _gdk_quartz_events_get_current_mouse_modifiers ();
-
- return found_window;
-}
-
+++ /dev/null
-/* GDK - The GIMP Drawing Kit
- * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-
-#include <gdk/gdktypes.h>
-#include <gdk/gdkdevicemanager.h>
-#include <gdk/gdkdeviceprivate.h>
-#include <gdk/gdkseatdefaultprivate.h>
-#include <gdk/gdkdevicemanagerprivate.h>
-#include "gdkdevicemanager-core-quartz.h"
-#include "gdkquartzdevice-core.h"
-#include "gdkkeysyms.h"
-#include "gdkprivate-quartz.h"
-
-
-#define HAS_FOCUS(toplevel) \
- ((toplevel)->has_focus || (toplevel)->has_pointer_focus)
-
-static void gdk_quartz_device_manager_core_finalize (GObject *object);
-static void gdk_quartz_device_manager_core_constructed (GObject *object);
-
-static GdkDevice * gdk_quartz_device_manager_core_get_client_pointer (GdkDeviceManager *device_manager);
-
-
-G_DEFINE_TYPE (GdkQuartzDeviceManagerCore, gdk_quartz_device_manager_core, G_TYPE_OBJECT)
-
-static void
-gdk_quartz_device_manager_core_class_init (GdkQuartzDeviceManagerCoreClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- object_class->finalize = gdk_quartz_device_manager_core_finalize;
- object_class->constructed = gdk_quartz_device_manager_core_constructed;
-}
-
-static GdkDevice *
-create_core_pointer (GdkQuartzDeviceManagerCore *device_manager,
- GdkDisplay *display)
-{
- return g_object_new (GDK_TYPE_QUARTZ_DEVICE_CORE,
- "name", "Core Pointer",
- "type", GDK_DEVICE_TYPE_LOGICAL,
- "input-source", GDK_SOURCE_MOUSE,
- "input-mode", GDK_MODE_SCREEN,
- "has-cursor", TRUE,
- "display", display,
- "device-manager", device_manager,
- NULL);
-}
-
-static GdkDevice *
-create_core_keyboard (GdkQuartzDeviceManagerCore *device_manager,
- GdkDisplay *display)
-{
- return g_object_new (GDK_TYPE_QUARTZ_DEVICE_CORE,
- "name", "Core Keyboard",
- "type", GDK_DEVICE_TYPE_LOGICAL,
- "input-source", GDK_SOURCE_KEYBOARD,
- "input-mode", GDK_MODE_SCREEN,
- "has-cursor", FALSE,
- "display", display,
- "device-manager", device_manager,
- NULL);
-}
-
-static void
-gdk_quartz_device_manager_core_init (GdkQuartzDeviceManagerCore *device_manager)
-{
-}
-
-static void
-gdk_quartz_device_manager_core_finalize (GObject *object)
-{
- GdkQuartzDeviceManagerCore *quartz_device_manager_core;
-
- quartz_device_manager_core = GDK_QUARTZ_DEVICE_MANAGER_CORE (object);
-
- g_object_unref (quartz_device_manager_core->core_pointer);
- g_object_unref (quartz_device_manager_core->core_keyboard);
-
- G_OBJECT_CLASS (gdk_quartz_device_manager_core_parent_class)->finalize (object);
-}
-
-static void
-gdk_quartz_device_manager_core_constructed (GObject *object)
-{
- GdkQuartzDeviceManagerCore *device_manager;
- GdkDisplay *display;
- GdkSeat *seat;
-
- display = _gdk_display;
-
- device_manager = GDK_QUARTZ_DEVICE_MANAGER_CORE (object);
- device_manager->core_pointer = create_core_pointer (GDK_DEVICE_MANAGER (device_manager), display);
- device_manager->core_keyboard = create_core_keyboard (GDK_DEVICE_MANAGER (device_manager), display);
-
- _gdk_device_set_associated_device (device_manager->core_pointer, device_manager->core_keyboard);
- _gdk_device_set_associated_device (device_manager->core_keyboard, device_manager->core_pointer);
-
- seat = gdk_seat_default_new_for_logical_pair (device_manager->core_pointer,
- device_manager->core_keyboard);
- gdk_display_add_seat (display, seat);
- g_object_unref (seat);
-}
+++ /dev/null
-/* gdkdevicemanager-quartz.h
- *
- * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
- * Copyright (C) 2010 Kristian Rietveld <kris@gtk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __GDK_QUARTZ_DEVICE_MANAGER_CORE__
-#define __GDK_QUARTZ_DEVICE_MANAGER_CORE__
-
-#include <gdkdevicemanagerprivate.h>
-#include "gdkquartzdevicemanager-core.h"
-
-G_BEGIN_DECLS
-
-struct _GdkQuartzDeviceManagerCore
-{
- GObject parent_object;
- GdkDevice *core_pointer;
- GdkDevice *core_keyboard;
-};
-
-struct _GdkQuartzDeviceManagerCoreClass
-{
- GObjectClass parent_class;
-};
-
-G_END_DECLS
-
-#endif /* __GDK_QUARTZ_DEVICE_MANAGER__ */
+++ /dev/null
-/* gdkdisplay-quartz.c
- *
- * Copyright (C) 2005 Imendio AB
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-
-#include <gdk/gdk.h>
-#include <gdk/gdkdisplayprivate.h>
-
-#include "gdkprivate-quartz.h"
-#include "gdkquartzscreen.h"
-#include "gdkquartzsurface.h"
-#include "gdkquartzdisplay.h"
-#include "gdkquartzdevicemanager-core.h"
-#include "gdkmonitorprivate.h"
-#include "gdkdisplay-quartz.h"
-#include "gdkcairocontext-quartz.h"
-
-
-static GdkSurface *
-gdk_quartz_display_get_default_group (GdkDisplay *display)
-{
- g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
-
- /* FIXME: Implement */
-
- return NULL;
-}
-
-GdkDeviceManager *
-_gdk_device_manager_new (GdkDisplay *display)
-{
- return g_object_new (GDK_TYPE_QUARTZ_DEVICE_MANAGER_CORE,
- "display", display,
- NULL);
-}
-
-GdkDisplay *
-_gdk_quartz_display_open (const gchar *display_name)
-{
- if (_gdk_display != NULL)
- return NULL;
-
- _gdk_display = g_object_new (gdk_quartz_display_get_type (), NULL);
- _gdk_device_manager = _gdk_device_manager_new (_gdk_display);
-
- _gdk_screen = g_object_new (gdk_quartz_screen_get_type (), NULL);
-
- _gdk_quartz_surface_init_windowing (_gdk_display);
-
- _gdk_quartz_events_init ();
-
- /* Initialize application */
- [NSApplication sharedApplication];
-#if 0
- /* FIXME: Remove the #if 0 when we have these functions */
- _gdk_quartz_dnd_init ();
-#endif
-
- g_signal_emit_by_name (_gdk_display, "opened");
-
- return _gdk_display;
-}
-
-static const gchar *
-gdk_quartz_display_get_name (GdkDisplay *display)
-{
- static gchar *display_name = NULL;
-
- if (!display_name)
- {
- GDK_QUARTZ_ALLOC_POOL;
- display_name = g_strdup ([[[NSHost currentHost] name] UTF8String]);
- GDK_QUARTZ_RELEASE_POOL;
- }
-
- return display_name;
-}
-
-static void
-gdk_quartz_display_beep (GdkDisplay *display)
-{
- g_return_if_fail (GDK_IS_DISPLAY (display));
-
- NSBeep();
-}
-
-static void
-gdk_quartz_display_sync (GdkDisplay *display)
-{
- /* Not supported. */
-}
-
-static void
-gdk_quartz_display_flush (GdkDisplay *display)
-{
- /* Not supported. */
-}
-
-static gboolean
-gdk_quartz_display_supports_shapes (GdkDisplay *display)
-{
- /* FIXME: Implement */
- return FALSE;
-}
-
-static gboolean
-gdk_quartz_display_supports_input_shapes (GdkDisplay *display)
-{
- /* FIXME: Implement */
- return FALSE;
-}
-
-static gulong
-gdk_quartz_display_get_next_serial (GdkDisplay *display)
-{
- return 0;
-}
-
-static void
-gdk_quartz_display_notify_startup_complete (GdkDisplay *display,
- const gchar *startup_id)
-{
- /* FIXME: Implement? */
-}
-
-static int
-gdk_quartz_display_get_n_monitors (GdkDisplay *display)
-{
- GdkQuartzDisplay *quartz_display = GDK_QUARTZ_DISPLAY (display);
-
- return quartz_display->monitors->len;
-}
-
-
-static GdkMonitor *
-gdk_quartz_display_get_monitor (GdkDisplay *display,
- int monitor_num)
-{
- GdkQuartzDisplay *quartz_display = GDK_QUARTZ_DISPLAY (display);
-
- if (0 <= monitor_num || monitor_num < quartz_display->monitors->len)
- return (GdkMonitor *)quartz_display->monitors->pdata[monitor_num];
-
- return NULL;
-}
-
-static gboolean
-gdk_quartz_display_get_setting (GdkDisplay *display,
- const gchar *name,
- GValue *value)
-{
- return _gdk_quartz_get_setting (name, value);
-}
-
-
-G_DEFINE_TYPE (GdkQuartzDisplay, gdk_quartz_display, GDK_TYPE_DISPLAY)
-
-static void
-gdk_quartz_display_init (GdkQuartzDisplay *display)
-{
- GDK_QUARTZ_ALLOC_POOL;
-
- display->monitors = g_ptr_array_new_with_free_func (g_object_unref);
-
- GDK_QUARTZ_RELEASE_POOL;
-}
-
-static void
-gdk_quartz_display_dispose (GObject *object)
-{
- GdkQuartzDisplay *display_quartz = GDK_QUARTZ_DISPLAY (object);
-
- g_ptr_array_free (display_quartz->monitors, TRUE);
-
- G_OBJECT_CLASS (gdk_quartz_display_parent_class)->dispose (object);
-}
-
-static void
-gdk_quartz_display_finalize (GObject *object)
-{
- GdkQuartzDisplay *display_quartz = GDK_QUARTZ_DISPLAY (object);
-
- G_OBJECT_CLASS (gdk_quartz_display_parent_class)->finalize (object);
-}
-
-static void
-gdk_quartz_display_class_init (GdkQuartzDisplayClass *class)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (class);
- GdkDisplayClass *display_class = GDK_DISPLAY_CLASS (class);
-
- object_class->finalize = gdk_quartz_display_finalize;
- object_class->dispose = gdk_quartz_display_dispose;
-
- display_class->surface_type = GDK_TYPE_QUARTZ_SURFACE;
- display_class->cairo_context_type = GDK_TYPE_QUARTZ_CAIRO_CONTEXT;
-
- display_class->get_name = gdk_quartz_display_get_name;
- display_class->beep = gdk_quartz_display_beep;
- display_class->sync = gdk_quartz_display_sync;
- display_class->flush = gdk_quartz_display_flush;
- display_class->queue_events = _gdk_quartz_display_queue_events;
- display_class->has_pending = _gdk_quartz_display_has_pending;
- display_class->get_default_group = gdk_quartz_display_get_default_group;
- display_class->supports_shapes = gdk_quartz_display_supports_shapes;
- display_class->supports_input_shapes = gdk_quartz_display_supports_input_shapes;
- display_class->get_default_cursor_size = _gdk_quartz_display_get_default_cursor_size;
- display_class->get_maximal_cursor_size = _gdk_quartz_display_get_maximal_cursor_size;
- display_class->supports_cursor_alpha = _gdk_quartz_display_supports_cursor_alpha;
- display_class->supports_cursor_color = _gdk_quartz_display_supports_cursor_color;
-
- display_class->get_next_serial = gdk_quartz_display_get_next_serial;
- display_class->notify_startup_complete = gdk_quartz_display_notify_startup_complete;
- display_class->event_data_copy = _gdk_quartz_display_event_data_copy;
- display_class->event_data_free = _gdk_quartz_display_event_data_free;
- display_class->create_surface_impl = _gdk_quartz_display_create_surface_impl;
- display_class->get_keymap = _gdk_quartz_display_get_keymap;
- display_class->get_n_monitors = gdk_quartz_display_get_n_monitors;
- display_class->get_monitor = gdk_quartz_display_get_monitor;
- display_class->get_setting = gdk_quartz_display_get_setting;
-
- ProcessSerialNumber psn = { 0, kCurrentProcess };
-
- /* Make the current process a foreground application, i.e. an app
- * with a user interface, in case we're not running from a .app bundle
- */
- TransformProcessType (&psn, kProcessTransformToForegroundApplication);
-}
+++ /dev/null
-/*
- * gdkdisplay-quartz.h
- *
- * Copyright 2017 Tom Schoonjans
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __GDK_QUARTZ_DISPLAY__
-#define __GDK_QUARTZ_DISPLAY__
-
-#include "gdkdisplayprivate.h"
-#include "gdkkeys.h"
-#include "gdksurface.h"
-#include "gdkinternals.h"
-
-G_BEGIN_DECLS
-
-
-struct _GdkQuartzDisplay
-{
- GdkDisplay parent_instance;
- GPtrArray *monitors;
-};
-
-struct _GdkQuartzDisplayClass
-{
- GdkDisplayClass parent_class;
-};
-
-/* Display methods - events */
-void _gdk_quartz_display_queue_events (GdkDisplay *display);
-gboolean _gdk_quartz_display_has_pending (GdkDisplay *display);
-
-void _gdk_quartz_display_event_data_copy (GdkDisplay *display,
- const GdkEvent *src,
- GdkEvent *dst);
-void _gdk_quartz_display_event_data_free (GdkDisplay *display,
- GdkEvent *event);
-
-/* Display methods - cursor */
-gboolean _gdk_quartz_display_supports_cursor_alpha (GdkDisplay *display);
-gboolean _gdk_quartz_display_supports_cursor_color (GdkDisplay *display);
-void _gdk_quartz_display_get_default_cursor_size (GdkDisplay *display,
- guint *width,
- guint *height);
-void _gdk_quartz_display_get_maximal_cursor_size (GdkDisplay *display,
- guint *width,
- guint *height);
-
-/* Display methods - window */
-void _gdk_quartz_display_before_process_all_updates (GdkDisplay *display);
-void _gdk_quartz_display_after_process_all_updates (GdkDisplay *display);
-void _gdk_quartz_display_create_surface_impl (GdkDisplay *display,
- GdkSurface *window,
- GdkSurface *real_parent,
- GdkSurfaceAttr *attributes);
-
-/* Display methods - keymap */
-GdkKeymap * _gdk_quartz_display_get_keymap (GdkDisplay *display);
-
-
-G_END_DECLS
-
-#endif /* __GDK_QUARTZ_DISPLAY__ */
-
+++ /dev/null
-/* GDK - The GIMP Drawing Kit
- * gdkdisplaymanager-quartz.c
- *
- * Copyright (C) 2005 Imendio AB
- * Copyright 2010 Red Hat, Inc.
- *
- * Author: Matthias clasen
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-
-#include <ApplicationServices/ApplicationServices.h>
-
-#include "gdkquartzdisplay.h"
-#include "gdkquartzdisplaymanager.h"
-#include "gdkprivate-quartz.h"
-
-#include "gdkdisplaymanagerprivate.h"
-#include "gdkinternals.h"
-
-struct _GdkQuartzDisplayManager
-{
- GdkDisplayManager parent;
-};
-
-
-G_DEFINE_TYPE (GdkQuartzDisplayManager, gdk_quartz_display_manager, GDK_TYPE_DISPLAY_MANAGER)
-
-static void
-gdk_quartz_display_manager_init (GdkQuartzDisplayManager *manager)
-{
-}
-
-static void
-gdk_quartz_display_manager_finalize (GObject *object)
-{
- g_error ("A GdkQuartzDisplayManager object was finalized. This should not happen");
- G_OBJECT_CLASS (gdk_quartz_display_manager_parent_class)->finalize (object);
-}
-
-static void
-gdk_quartz_display_manager_class_init (GdkQuartzDisplayManagerClass *class)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (class);
- GdkDisplayManagerClass *manager_class = GDK_DISPLAY_MANAGER_CLASS (class);
-
- object_class->finalize = gdk_quartz_display_manager_finalize;
-}
+++ /dev/null
-/* gdkdnd-quartz.c
- *
- * Copyright (C) 2005 Imendio AB
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-#include "gdkdnd.h"
-#include "gdkquartzdnd.h"
-#include "gdkprivate-quartz.h"
-
-
-G_DEFINE_TYPE (GdkQuartzDragContext, gdk_quartz_drag_context, GDK_TYPE_DRAG_CONTEXT)
-
-
-GdkDragContext *_gdk_quartz_drag_source_context = NULL;
-
-GdkDragContext *
-gdk_quartz_drag_source_context_libgtk_only ()
-{
- return _gdk_quartz_drag_source_context;
-}
-
-GdkDragContext *
-_gdk_quartz_surface_drag_begin (GdkSurface *window,
- GdkDevice *device,
- GList *targets,
- gint dx,
- gint dy)
-{
- g_assert (_gdk_quartz_drag_source_context == NULL);
-
- /* Create fake context */
- _gdk_quartz_drag_source_context = g_object_new (GDK_TYPE_QUARTZ_DRAG_CONTEXT,
- "device", device,
- NULL);
-
- _gdk_quartz_drag_source_context->source_surface = window;
- g_object_ref (window);
-
- _gdk_quartz_drag_source_context->targets = targets;
-
- return _gdk_quartz_drag_source_context;
-}
-
-static void
-gdk_quartz_drag_context_drag_drop (GdkDragContext *context,
- guint32 time)
-{
- /* FIXME: Implement */
-}
-
-static void
-gdk_quartz_drag_context_drag_abort (GdkDragContext *context,
- guint32 time)
-{
- /* FIXME: Implement */
-}
-
-id
-gdk_quartz_drag_context_get_dragging_info_libgtk_only (GdkDragContext *context)
-{
- return GDK_QUARTZ_DRAG_CONTEXT (context)->dragging_info;
-}
-
-static void
-gdk_quartz_drag_context_init (GdkQuartzDragContext *context)
-{
-}
-
-static void
-gdk_quartz_drag_context_finalize (GObject *object)
-{
- G_OBJECT_CLASS (gdk_quartz_drag_context_parent_class)->finalize (object);
-}
-
-static void
-gdk_quartz_drag_context_class_init (GdkQuartzDragContextClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GdkDragContextClass *context_class = GDK_DRAG_CONTEXT_CLASS (klass);
-
- object_class->finalize = gdk_quartz_drag_context_finalize;
-
- context_class->drag_abort = gdk_quartz_drag_context_drag_abort;
- context_class->drag_drop = gdk_quartz_drag_context_drag_drop;
-}
+++ /dev/null
-/* gdkdnd-quartz.h
- *
- * Copyright (C) 2005 Imendio AB
- * Copyright (C) 2010 Kristian Rietveld <kris@gtk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __GDK_QUARTZ_DND__
-#define __GDK_QUARTZ_DND__
-
-#include <gdkdndprivate.h>
-#include "gdkquartzdnd.h"
-
-#include <AppKit/AppKit.h>
-
-G_BEGIN_DECLS
-
-struct _GdkQuartzDragContext
-{
- GdkDragContext context;
-
- id <NSDraggingInfo> dragging_info;
- GdkDevice *device;
-};
-
-struct _GdkQuartzDragContextClass
-{
- GdkDragContextClass context_class;
-};
-
-G_END_DECLS
-
-#endif /* __GDK_QUARTZ_DND__ */
+++ /dev/null
-#include "config.h"
-
-#include <glib.h>
-#include <pthread.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <unistd.h>
-
-#include "gdkprivate-quartz.h"
-#include <gdk/gdkdisplayprivate.h>
-
-/*
- * This file implementations integration between the GLib main loop and
- * the native system of the Core Foundation run loop and Cocoa event
- * handling. There are basically two different cases that we need to
- * handle: either the GLib main loop is in control (the application
- * has called gtk_main(), or is otherwise iterating the main loop), or
- * CFRunLoop is in control (we are in a modal operation such as window
- * resizing or drag-and-drop.)
- *
- * When the GLib main loop is in control we integrate in native event
- * handling in two ways: first we add a GSource that handles checking
- * whether there are native events available, translating native events
- * to GDK events, and dispatching GDK events. Second we replace the
- * "poll function" of the GLib main loop with our own version that knows
- * how to wait for both the file descriptors and timeouts that GLib is
- * interested in and also for incoming native events.
- *
- * When CFRunLoop is in control, we integrate in GLib main loop handling
- * by adding a "run loop observer" that gives us notification at various
- * points in the run loop cycle. We map these points onto the corresponding
- * stages of the GLib main loop (prepare, check, dispatch), and make the
- * appropriate calls into GLib.
- *
- * Both cases share a single problem: the OS X API’s don’t allow us to
- * wait simultaneously for file descriptors and for events. So when we
- * need to do a blocking wait that includes file descriptor activity, we
- * push the actual work of calling select() to a helper thread (the
- * "select thread") and wait for native events in the main thread.
- *
- * The main known limitation of this code is that if a callback is triggered
- * via the OS X run loop while we are "polling" (in either case described
- * above), iteration of the GLib main loop is not possible from within
- * that callback. If the programmer tries to do so explicitly, then they
- * will get a warning from GLib "main loop already active in another thread".
- */
-
-/******* State for run loop iteration *******/
-
-/* Count of number of times we've gotten an "Entry" notification for
- * our run loop observer.
- */
-static int current_loop_level = 0;
-
-/* Run loop level at which we acquired ownership of the GLib main
- * loop. See note in run_loop_entry(). -1 means that we don’t have
- * ownership
- */
-static int acquired_loop_level = -1;
-
-/* Between run_loop_before_waiting() and run_loop_after_waiting();
- * whether we need to call select_thread_collect_poll()
- */
-static gboolean run_loop_polling_async = FALSE;
-
-/* Between run_loop_before_waiting() and run_loop_after_waiting();
- * max_priority to pass to g_main_loop_check()
- */
-static gint run_loop_max_priority;
-
-/* Timer that we've added to wake up the run loop when a GLib timeout
- */
-static CFRunLoopTimerRef run_loop_timer = NULL;
-
-/* These are the file descriptors that are we are polling out of
- * the run loop. (We keep the array around and reuse it to avoid
- * constant allocations.)
- */
-#define RUN_LOOP_POLLFDS_INITIAL_SIZE 16
-static GPollFD *run_loop_pollfds;
-static guint run_loop_pollfds_size; /* Allocated size of the array */
-static guint run_loop_n_pollfds; /* Number of file descriptors in the array */
-
-/******* Other global variables *******/
-
-/* Since we count on replacing the GLib main loop poll function as our
- * method of integrating Cocoa event handling into the GLib main loop
- * we need to make sure that the poll function is always called even
- * when there are no file descriptors that need to be polled. To do
- * this, we add a dummy GPollFD to our event source with a file
- * descriptor of “-1”. Then any time that GLib is polling the event
- * source, it will call our poll function.
- */
-static GPollFD event_poll_fd;
-
-/* Current NSEvents that we've gotten from Cocoa but haven't yet converted
- * to GdkEvents. We wait until our dispatch() function to do the conversion
- * since the conversion can conceivably cause signals to be emitted
- * or other things that shouldn’t happen inside a poll function.
- */
-static GQueue *current_events;
-
-/* The default poll function for GLib; we replace this with our own
- * Cocoa-aware version and then call the old version to do actual
- * file descriptor polling. There’s no actual need to chain to the
- * old one; we could reimplement the same functionality from scratch,
- * but since the default implementation does the right thing, why
- * bother.
- */
-static GPollFunc old_poll_func;
-
-/* Reference to the run loop of the main thread. (There is a unique
- * CFRunLoop per thread.)
- */
-static CFRunLoopRef main_thread_run_loop;
-
-/* Normally the Cocoa main loop maintains an NSAutoReleasePool and frees
- * it on every iteration. Since we are replacing the main loop we have
- * to provide this functionality ourself. We free and replace the
- * auto-release pool in our sources prepare() function.
- */
-static NSAutoreleasePool *autorelease_pool;
-
-/* Flag when we've called nextEventMatchingMask ourself; this triggers
- * a run loop iteration, so we need to detect that and avoid triggering
- * our "run the GLib main looop while the run loop is active machinery.
- */
-static gint getting_events = 0;
-
-/************************************************************
- ********* Select Thread *********
- ************************************************************/
-
-/* The states in our state machine, see comments in select_thread_func()
- * for descriptions of each state
- */
-typedef enum {
- BEFORE_START,
- WAITING,
- POLLING_QUEUED,
- POLLING_RESTART,
- POLLING_DESCRIPTORS,
-} SelectThreadState;
-
-#ifdef G_ENABLE_DEBUG
-static const char *const state_names[] = {
- "BEFORE_START",
- "WAITING",
- "POLLING_QUEUED",
- "POLLING_RESTART",
- "POLLING_DESCRIPTORS"
-};
-#endif
-
-static SelectThreadState select_thread_state = BEFORE_START;
-
-static pthread_t select_thread;
-static pthread_mutex_t select_thread_mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t select_thread_cond = PTHREAD_COND_INITIALIZER;
-
-#define SELECT_THREAD_LOCK() pthread_mutex_lock (&select_thread_mutex)
-#define SELECT_THREAD_UNLOCK() pthread_mutex_unlock (&select_thread_mutex)
-#define SELECT_THREAD_SIGNAL() pthread_cond_signal (&select_thread_cond)
-#define SELECT_THREAD_WAIT() pthread_cond_wait (&select_thread_cond, &select_thread_mutex)
-
-/* These are the file descriptors that the select thread is currently
- * polling.
- */
-static GPollFD *current_pollfds;
-static guint current_n_pollfds;
-
-/* These are the file descriptors that the select thread should pick
- * up and start polling when it has a chance.
- */
-static GPollFD *next_pollfds;
-static guint next_n_pollfds;
-
-/* Pipe used to wake up the select thread */
-static gint select_thread_wakeup_pipe[2];
-
-/* Run loop source used to wake up the main thread */
-static CFRunLoopSourceRef select_main_thread_source;
-
-static void
-select_thread_set_state (SelectThreadState new_state)
-{
- gboolean old_state;
-
- if (select_thread_state == new_state)
- return;
-
- GDK_NOTE (EVENTLOOP, g_message ("EventLoop: Select thread state: %s => %s", state_names[select_thread_state], state_names[new_state]));
-
- old_state = select_thread_state;
- select_thread_state = new_state;
- if (old_state == WAITING && new_state != WAITING)
- SELECT_THREAD_SIGNAL ();
-}
-
-static void
-signal_main_thread (void)
-{
- GDK_NOTE (EVENTLOOP, g_message ("EventLoop: Waking up main thread"));
-
- /* If we are in nextEventMatchingMask, then we need to make sure an
- * event gets queued, otherwise it's enough to simply wake up the
- * main thread run loop
- */
- if (!run_loop_polling_async)
- CFRunLoopSourceSignal (select_main_thread_source);
-
- /* Don't check for CFRunLoopIsWaiting() here because it causes a
- * race condition (the loop could go into waiting state right after
- * we checked).
- */
- CFRunLoopWakeUp (main_thread_run_loop);
-}
-
-static void *
-select_thread_func (void *arg)
-{
- char c;
-
- SELECT_THREAD_LOCK ();
-
- while (TRUE)
- {
- switch (select_thread_state)
- {
- case BEFORE_START:
- /* The select thread has not been started yet
- */
- g_assert_not_reached ();
-
- case WAITING:
- /* Waiting for a set of file descriptors to be submitted by the main thread
- *
- * => POLLING_QUEUED: main thread submits a set of file descriptors
- */
- SELECT_THREAD_WAIT ();
- break;
-
- case POLLING_QUEUED:
- /* Waiting for a set of file descriptors to be submitted by the main thread
- *
- * => POLLING_DESCRIPTORS: select thread picks up the file descriptors to begin polling
- */
- g_free (current_pollfds);
-
- current_pollfds = next_pollfds;
- current_n_pollfds = next_n_pollfds;
-
- next_pollfds = NULL;
- next_n_pollfds = 0;
-
- select_thread_set_state (POLLING_DESCRIPTORS);
- break;
-
- case POLLING_RESTART:
- /* Select thread is currently polling a set of file descriptors, main thread has
- * began a new iteration with the same set of file descriptors. We don't want to
- * wake the select thread up and wait for it to restart immediately, but to avoid
- * a race (described below in select_thread_start_polling()) we need to recheck after
- * polling completes.
- *
- * => POLLING_DESCRIPTORS: select completes, main thread rechecks by polling again
- * => POLLING_QUEUED: main thread submits a new set of file descriptors to be polled
- */
- select_thread_set_state (POLLING_DESCRIPTORS);
- break;
-
- case POLLING_DESCRIPTORS:
- /* In the process of polling the file descriptors
- *
- * => WAITING: polling completes when a file descriptor becomes active
- * => POLLING_QUEUED: main thread submits a new set of file descriptors to be polled
- * => POLLING_RESTART: main thread begins a new iteration with the same set file descriptors
- */
- SELECT_THREAD_UNLOCK ();
- old_poll_func (current_pollfds, current_n_pollfds, -1);
- SELECT_THREAD_LOCK ();
-
- read (select_thread_wakeup_pipe[0], &c, 1);
-
- if (select_thread_state == POLLING_DESCRIPTORS)
- {
- signal_main_thread ();
- select_thread_set_state (WAITING);
- }
- break;
- }
- }
-}
-
-static void
-got_fd_activity (void *info)
-{
- NSEvent *event;
-
- /* Post a message so we'll break out of the message loop */
- event = [NSEvent otherEventWithType: NSApplicationDefined
- location: NSZeroPoint
- modifierFlags: 0
- timestamp: 0
- windowNumber: 0
- context: nil
- subtype: GDK_QUARTZ_EVENT_SUBTYPE_EVENTLOOP
- data1: 0
- data2: 0];
-
- [NSApp postEvent:event atStart:YES];
-}
-
-static void
-select_thread_start (void)
-{
- g_return_if_fail (select_thread_state == BEFORE_START);
-
- pipe (select_thread_wakeup_pipe);
- fcntl (select_thread_wakeup_pipe[0], F_SETFL, O_NONBLOCK);
-
- CFRunLoopSourceContext source_context = {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, got_fd_activity };
- select_main_thread_source = CFRunLoopSourceCreate (NULL, 0, &source_context);
-
- CFRunLoopAddSource (main_thread_run_loop, select_main_thread_source, kCFRunLoopCommonModes);
-
- select_thread_state = WAITING;
-
- while (TRUE)
- {
- if (pthread_create (&select_thread, NULL, select_thread_func, NULL) == 0)
- break;
-
- g_warning ("Failed to create select thread, sleeping and trying again");
- sleep (1);
- }
-}
-
-#ifdef G_ENABLE_DEBUG
-static void
-dump_poll_result (GPollFD *ufds,
- guint nfds)
-{
- GString *s;
- gint i;
-
- s = g_string_new ("");
- for (i = 0; i < nfds; i++)
- {
- if (ufds[i].fd >= 0 && ufds[i].revents)
- {
- g_string_append_printf (s, " %d:", ufds[i].fd);
- if (ufds[i].revents & G_IO_IN)
- g_string_append (s, " in");
- if (ufds[i].revents & G_IO_OUT)
- g_string_append (s, " out");
- if (ufds[i].revents & G_IO_PRI)
- g_string_append (s, " pri");
- g_string_append (s, "\n");
- }
- }
- g_message ("%s", s->str);
- g_string_free (s, TRUE);
-}
-#endif
-
-gboolean
-pollfds_equal (GPollFD *old_pollfds,
- guint old_n_pollfds,
- GPollFD *new_pollfds,
- guint new_n_pollfds)
-{
- gint i;
-
- if (old_n_pollfds != new_n_pollfds)
- return FALSE;
-
- for (i = 0; i < old_n_pollfds; i++)
- {
- if (old_pollfds[i].fd != new_pollfds[i].fd ||
- old_pollfds[i].events != new_pollfds[i].events)
- return FALSE;
- }
-
- return TRUE;
-}
-
-/* Begins a polling operation with the specified GPollFD array; the
- * timeout is used only to tell if the polling operation is blocking
- * or non-blocking.
- *
- * Returns:
- * -1: No file descriptors ready, began asynchronous poll
- * 0: No file descriptors ready, asynchronous poll not needed
- * > 0: Number of file descriptors ready
- */
-static gint
-select_thread_start_poll (GPollFD *ufds,
- guint nfds, gint timeout)
-{
- gint n_ready;
- gboolean have_new_pollfds = FALSE;
- gint poll_fd_index = -1;
- gint i;
-
- for (i = 0; i < nfds; i++)
- if (ufds[i].fd == -1)
- {
- poll_fd_index = i;
- break;
- }
-
- if (nfds == 0 ||
- (nfds == 1 && poll_fd_index >= 0))
- {
- GDK_NOTE (EVENTLOOP, g_message ("EventLoop: Nothing to poll"));
- return 0;
- }
-
- /* If we went immediately to an async poll, then we might decide to
- * dispatch idle functions when higher priority file descriptor sources
- * are ready to be dispatched. So we always need to first check
- * check synchronously with a timeout of zero, and only when no
- * sources are immediately ready, go to the asynchronous poll.
- *
- * Of course, if the timeout passed in is 0, then the synchronous
- * check is sufficient and we never need to do the asynchronous poll.
- */
- n_ready = old_poll_func (ufds, nfds, 0);
- if (n_ready > 0 || timeout == 0)
- {
-#ifdef G_ENABLE_DEBUG
- if ((_gdk_debug_flags & GDK_DEBUG_EVENTLOOP) && n_ready > 0)
- {
- g_message ("EventLoop: Found ready file descriptors before waiting");
- dump_poll_result (ufds, nfds);
- }
-#endif
-
- return n_ready;
- }
-
- SELECT_THREAD_LOCK ();
-
- if (select_thread_state == BEFORE_START)
- {
- select_thread_start ();
- }
-
- if (select_thread_state == POLLING_QUEUED)
- {
- /* If the select thread hasn't picked up the set of file descriptors yet
- * then we can simply replace an old stale set with a new set.
- */
- if (!pollfds_equal (ufds, nfds, next_pollfds, next_n_pollfds - 1))
- {
- g_free (next_pollfds);
- next_pollfds = NULL;
- next_n_pollfds = 0;
-
- have_new_pollfds = TRUE;
- }
- }
- else if (select_thread_state == POLLING_RESTART || select_thread_state == POLLING_DESCRIPTORS)
- {
- /* If we are already in the process of polling the right set of file descriptors,
- * there's no need for us to immediately force the select thread to stop polling
- * and then restart again. And avoiding doing so increases the efficiency considerably
- * in the common case where we have a set of basically inactive file descriptors that
- * stay unchanged present as we process many events.
- *
- * However, we have to be careful that we don't hit the following race condition
- * Select Thread Main Thread
- * ----------------- ---------------
- * Polling Completes
- * Reads data or otherwise changes file descriptor state
- * Checks if polling is current
- * Does nothing (*)
- * Releases lock
- * Acquires lock
- * Marks polling as complete
- * Wakes main thread
- * Receives old stale file descriptor state
- *
- * To avoid this, when the new set of poll descriptors is the same as the current
- * one, we transition to the POLLING_RESTART stage at the point marked (*). When
- * the select thread wakes up from the poll because a file descriptor is active, if
- * the state is POLLING_RESTART it immediately begins polling same the file descriptor
- * set again. This normally will just return the same set of active file descriptors
- * as the first time, but in sequence described above will properly update the
- * file descriptor state.
- *
- * Special case: this RESTART logic is not needed if the only FD is the internal GLib
- * "wakeup pipe" that is presented when threads are initialized.
- *
- * P.S.: The harm in the above sequence is mostly that sources can be signalled
- * as ready when they are no longer ready. This may prompt a blocking read
- * from a file descriptor that hangs.
- */
- if (!pollfds_equal (ufds, nfds, current_pollfds, current_n_pollfds - 1))
- have_new_pollfds = TRUE;
- else
- {
- if (!((nfds == 1 && poll_fd_index < 0 && g_thread_supported ()) ||
- (nfds == 2 && poll_fd_index >= 0 && g_thread_supported ())))
- select_thread_set_state (POLLING_RESTART);
- }
- }
- else
- have_new_pollfds = TRUE;
-
- if (have_new_pollfds)
- {
- GDK_NOTE (EVENTLOOP, g_message ("EventLoop: Submitting a new set of file descriptor to the select thread"));
-
- g_assert (next_pollfds == NULL);
-
- next_n_pollfds = nfds + 1;
- next_pollfds = g_new (GPollFD, nfds + 1);
- memcpy (next_pollfds, ufds, nfds * sizeof (GPollFD));
-
- next_pollfds[nfds].fd = select_thread_wakeup_pipe[0];
- next_pollfds[nfds].events = G_IO_IN;
-
- if (select_thread_state != POLLING_QUEUED && select_thread_state != WAITING)
- {
- if (select_thread_wakeup_pipe[1])
- {
- char c = 'A';
- write (select_thread_wakeup_pipe[1], &c, 1);
- }
- }
-
- select_thread_set_state (POLLING_QUEUED);
- }
-
- SELECT_THREAD_UNLOCK ();
-
- return -1;
-}
-
-/* End an asynchronous polling operation started with
- * select_thread_collect_poll(). This must be called if and only if
- * select_thread_start_poll() return -1. The GPollFD array passed
- * in must be identical to the one passed to select_thread_start_poll().
- *
- * The results of the poll are written into the GPollFD array passed in.
- *
- * Returns: number of file descriptors ready
- */
-static int
-select_thread_collect_poll (GPollFD *ufds, guint nfds)
-{
- gint i;
- gint n_ready = 0;
-
- SELECT_THREAD_LOCK ();
-
- if (select_thread_state == WAITING) /* The poll completed */
- {
- for (i = 0; i < nfds; i++)
- {
- if (ufds[i].fd == -1)
- continue;
-
- g_assert (ufds[i].fd == current_pollfds[i].fd);
- g_assert (ufds[i].events == current_pollfds[i].events);
-
- if (current_pollfds[i].revents)
- {
- ufds[i].revents = current_pollfds[i].revents;
- n_ready++;
- }
- }
-
-#ifdef G_ENABLE_DEBUG
- if (_gdk_debug_flags & GDK_DEBUG_EVENTLOOP)
- {
- g_message ("EventLoop: Found ready file descriptors after waiting");
- dump_poll_result (ufds, nfds);
- }
-#endif
- }
-
- SELECT_THREAD_UNLOCK ();
-
- return n_ready;
-}
-
-/************************************************************
- ********* Main Loop Source *********
- ************************************************************/
-
-gboolean
-_gdk_quartz_event_loop_check_pending (void)
-{
- return current_events && current_events->head;
-}
-
-NSEvent*
-_gdk_quartz_event_loop_get_pending (void)
-{
- NSEvent *event = NULL;
-
- if (current_events)
- event = g_queue_pop_tail (current_events);
-
- return event;
-}
-
-void
-_gdk_quartz_event_loop_release_event (NSEvent *event)
-{
- [event release];
-}
-
-static gboolean
-gdk_event_prepare (GSource *source,
- gint *timeout)
-{
- gboolean retval;
-
- /* The prepare stage is the stage before the main loop starts polling
- * and dispatching events. The autorelease poll is drained here for
- * the preceding main loop iteration or, in case of the first iteration,
- * for the operations carried out between event loop initialization and
- * this first iteration.
- *
- * The autorelease poll must only be drained when the following conditions
- * apply:
- * - We are at the base CFRunLoop level (indicated by current_loop_level),
- * - We are at the base g_main_loop level (indicated by
- * g_main_depth())
- * - We are at the base poll_func level (indicated by getting events).
- *
- * Messing with the autorelease pool at any level of nesting can cause access
- * to deallocated memory because autorelease_pool is static and releasing a
- * pool will cause all pools allocated inside of it to be released as well.
- */
- if (current_loop_level == 0 && g_main_depth() == 0 && getting_events == 0)
- {
- if (autorelease_pool)
- [autorelease_pool drain];
-
- autorelease_pool = [[NSAutoreleasePool alloc] init];
- }
-
- *timeout = -1;
-
- if (_gdk_display->event_pause_count > 0)
- retval = _gdk_event_queue_find_first (_gdk_display) != NULL;
- else
- retval = (_gdk_event_queue_find_first (_gdk_display) != NULL ||
- _gdk_quartz_event_loop_check_pending ());
-
- return retval;
-}
-
-static gboolean
-gdk_event_check (GSource *source)
-{
- gboolean retval;
-
- if (_gdk_display->event_pause_count > 0)
- retval = _gdk_event_queue_find_first (_gdk_display) != NULL;
- else
- retval = (_gdk_event_queue_find_first (_gdk_display) != NULL ||
- _gdk_quartz_event_loop_check_pending ());
-
- return retval;
-}
-
-static gboolean
-gdk_event_dispatch (GSource *source,
- GSourceFunc callback,
- gpointer user_data)
-{
- GdkEvent *event;
-
- _gdk_quartz_display_queue_events (_gdk_display);
-
- event = _gdk_event_unqueue (_gdk_display);
-
- if (event)
- {
- _gdk_event_emit (event);
-
- g_object_unref (event);
- }
-
- return TRUE;
-}
-
-static GSourceFuncs event_funcs = {
- gdk_event_prepare,
- gdk_event_check,
- gdk_event_dispatch,
- NULL
-};
-
-/************************************************************
- ********* Our Poll Function *********
- ************************************************************/
-
-static gint
-poll_func (GPollFD *ufds,
- guint nfds,
- gint timeout_)
-{
- NSEvent *event;
- NSDate *limit_date;
- gint n_ready;
-
- static GPollFD *last_ufds;
-
- last_ufds = ufds;
-
- n_ready = select_thread_start_poll (ufds, nfds, timeout_);
- if (n_ready > 0)
- timeout_ = 0;
-
- if (timeout_ == -1)
- limit_date = [NSDate distantFuture];
- else if (timeout_ == 0)
- limit_date = [NSDate distantPast];
- else
- limit_date = [NSDate dateWithTimeIntervalSinceNow:timeout_/1000.0];
-
- getting_events++;
- event = [NSApp nextEventMatchingMask: NSAnyEventMask
- untilDate: limit_date
- inMode: NSDefaultRunLoopMode
- dequeue: YES];
- getting_events--;
-
- /* We check if last_ufds did not change since the time this function was
- * called. It is possible that a recursive main loop (and thus recursive
- * invocation of this poll function) is triggered while in
- * nextEventMatchingMask:. If during that time new fds are added,
- * the cached fds array might be replaced in g_main_context_iterate().
- * So, we should avoid accessing the old fd array (still pointed at by
- * ufds) here in that case, since it might have been freed. We avoid this
- * by not calling the collect stage.
- */
- if (last_ufds == ufds && n_ready < 0)
- n_ready = select_thread_collect_poll (ufds, nfds);
-
- if (event &&
- [event type] == NSApplicationDefined &&
- [event subtype] == GDK_QUARTZ_EVENT_SUBTYPE_EVENTLOOP)
- {
- /* Just used to wake us up; if an event and a FD arrived at the same
- * time; could have come from a previous iteration in some cases,
- * but the spurious wake up is harmless if a little inefficient.
- */
- event = NULL;
- }
-
- if (event)
- {
- if (!current_events)
- current_events = g_queue_new ();
- g_queue_push_head (current_events, [event retain]);
- }
-
- return n_ready;
-}
-
-/************************************************************
- ********* Running the main loop out of CFRunLoop *********
- ************************************************************/
-
-/* Wrapper around g_main_context_query() that handles reallocating
- * run_loop_pollfds up to the proper size
- */
-static gint
-query_main_context (GMainContext *context,
- int max_priority,
- int *timeout)
-{
- gint nfds;
-
- if (!run_loop_pollfds)
- {
- run_loop_pollfds_size = RUN_LOOP_POLLFDS_INITIAL_SIZE;
- run_loop_pollfds = g_new (GPollFD, run_loop_pollfds_size);
- }
-
- while ((nfds = g_main_context_query (context, max_priority, timeout,
- run_loop_pollfds,
- run_loop_pollfds_size)) > run_loop_pollfds_size)
- {
- g_free (run_loop_pollfds);
- run_loop_pollfds_size = nfds;
- run_loop_pollfds = g_new (GPollFD, nfds);
- }
-
- return nfds;
-}
-
-static void
-run_loop_entry (void)
-{
- if (acquired_loop_level == -1)
- {
- if (g_main_context_acquire (NULL))
- {
- GDK_NOTE (EVENTLOOP, g_message ("EventLoop: Beginning tracking run loop activity"));
- acquired_loop_level = current_loop_level;
- }
- else
- {
- /* If we fail to acquire the main context, that means someone is iterating
- * the main context in a different thread; we simply wait until this loop
- * exits and then try again at next entry. In general, iterating the loop
- * from a different thread is rare: it is only possible when GDK threading
- * is initialized and is not frequently used even then. So, we hope that
- * having GLib main loop iteration blocked in the combination of that and
- * a native modal operation is a minimal problem. We could imagine using a
- * thread that does g_main_context_wait() and then wakes us back up, but
- * the gain doesn't seem worth the complexity.
- */
- GDK_NOTE (EVENTLOOP, g_message ("EventLoop: Can't acquire main loop; skipping tracking run loop activity"));
- }
- }
-}
-
-static void
-run_loop_before_timers (void)
-{
-}
-
-static void
-run_loop_before_sources (void)
-{
- GMainContext *context = g_main_context_default ();
- gint max_priority;
- gint nfds;
-
- /* Before we let the CFRunLoop process sources, we want to check if there
- * are any pending GLib main loop sources more urgent than
- * G_PRIORITY_DEFAULT that need to be dispatched. (We consider all activity
- * from the CFRunLoop to have a priority of G_PRIORITY_DEFAULT.) If no
- * sources are processed by the CFRunLoop, then processing will continue
- * on to the BeforeWaiting stage where we check for lower priority sources.
- */
-
- g_main_context_prepare (context, &max_priority);
- max_priority = MIN (max_priority, G_PRIORITY_DEFAULT);
-
- /* We ignore the timeout that query_main_context () returns since we'll
- * always query again before waiting.
- */
- nfds = query_main_context (context, max_priority, NULL);
-
- if (nfds)
- old_poll_func (run_loop_pollfds, nfds, 0);
-
- if (g_main_context_check (context, max_priority, run_loop_pollfds, nfds))
- {
- GDK_NOTE (EVENTLOOP, g_message ("EventLoop: Dispatching high priority sources"));
- g_main_context_dispatch (context);
- }
-}
-
-static void
-dummy_timer_callback (CFRunLoopTimerRef timer,
- void *info)
-{
- /* Nothing; won't normally even be called */
-}
-
-static void
-run_loop_before_waiting (void)
-{
- GMainContext *context = g_main_context_default ();
- gint timeout;
- gint n_ready;
-
- /* At this point, the CFRunLoop is ready to wait. We start a GMain loop
- * iteration by calling the check() and query() stages. We start a
- * poll, and if it doesn't complete immediately we let the run loop
- * go ahead and sleep. Before doing that, if there was a timeout from
- * GLib, we set up a CFRunLoopTimer to wake us up.
- */
-
- g_main_context_prepare (context, &run_loop_max_priority);
-
- run_loop_n_pollfds = query_main_context (context, run_loop_max_priority, &timeout);
-
- n_ready = select_thread_start_poll (run_loop_pollfds, run_loop_n_pollfds, timeout);
-
- if (n_ready > 0 || timeout == 0)
- {
- /* We have stuff to do, no sleeping allowed! */
- CFRunLoopWakeUp (main_thread_run_loop);
- }
- else if (timeout > 0)
- {
- /* We need to get the run loop to break out of its wait when our timeout
- * expires. We do this by adding a dummy timer that we'll remove immediately
- * after the wait wakes up.
- */
- GDK_NOTE (EVENTLOOP, g_message ("EventLoop: Adding timer to wake us up in %d milliseconds", timeout));
-
- run_loop_timer = CFRunLoopTimerCreate (NULL, /* allocator */
- CFAbsoluteTimeGetCurrent () + timeout / 1000.,
- 0, /* interval (0=does not repeat) */
- 0, /* flags */
- 0, /* order (priority) */
- dummy_timer_callback,
- NULL);
-
- CFRunLoopAddTimer (main_thread_run_loop, run_loop_timer, kCFRunLoopCommonModes);
- }
-
- run_loop_polling_async = n_ready < 0;
-}
-
-static void
-run_loop_after_waiting (void)
-{
- GMainContext *context = g_main_context_default ();
-
- /* After sleeping, we finish of the GMain loop iteratin started in before_waiting()
- * by doing the check() and dispatch() stages.
- */
-
- if (run_loop_timer)
- {
- CFRunLoopRemoveTimer (main_thread_run_loop, run_loop_timer, kCFRunLoopCommonModes);
- CFRelease (run_loop_timer);
- run_loop_timer = NULL;
- }
-
- if (run_loop_polling_async)
- {
- select_thread_collect_poll (run_loop_pollfds, run_loop_n_pollfds);
- run_loop_polling_async = FALSE;
- }
-
- if (g_main_context_check (context, run_loop_max_priority, run_loop_pollfds, run_loop_n_pollfds))
- {
- GDK_NOTE (EVENTLOOP, g_message ("EventLoop: Dispatching after waiting"));
- g_main_context_dispatch (context);
- }
-}
-
-static void
-run_loop_exit (void)
-{
- /* + 1 because we decrement current_loop_level separately in observer_callback() */
- if ((current_loop_level + 1) == acquired_loop_level)
- {
- g_main_context_release (NULL);
- acquired_loop_level = -1;
- GDK_NOTE (EVENTLOOP, g_message ("EventLoop: Ended tracking run loop activity"));
- }
-}
-
-static void
-run_loop_observer_callback (CFRunLoopObserverRef observer,
- CFRunLoopActivity activity,
- void *info)
-{
- switch (activity)
- {
- case kCFRunLoopEntry:
- current_loop_level++;
- break;
- case kCFRunLoopExit:
- g_return_if_fail (current_loop_level > 0);
- current_loop_level--;
- break;
- default:
- break;
- }
-
- if (getting_events > 0) /* Activity we triggered */
- return;
-
- switch (activity)
- {
- case kCFRunLoopEntry:
- run_loop_entry ();
- break;
- case kCFRunLoopBeforeTimers:
- run_loop_before_timers ();
- break;
- case kCFRunLoopBeforeSources:
- run_loop_before_sources ();
- break;
- case kCFRunLoopBeforeWaiting:
- run_loop_before_waiting ();
- break;
- case kCFRunLoopAfterWaiting:
- run_loop_after_waiting ();
- break;
- case kCFRunLoopExit:
- run_loop_exit ();
- break;
- default:
- break;
- }
-}
-
-/************************************************************/
-
-void
-_gdk_quartz_event_loop_init (void)
-{
- GSource *source;
- CFRunLoopObserverRef observer;
-
- /* Hook into the GLib main loop */
-
- event_poll_fd.events = G_IO_IN;
- event_poll_fd.fd = -1;
-
- source = g_source_new (&event_funcs, sizeof (GSource));
- g_source_set_name (source, "GDK Quartz event source");
- g_source_add_poll (source, &event_poll_fd);
- g_source_set_priority (source, GDK_PRIORITY_EVENTS);
- g_source_set_can_recurse (source, TRUE);
- g_source_attach (source, NULL);
-
- old_poll_func = g_main_context_get_poll_func (NULL);
- g_main_context_set_poll_func (NULL, poll_func);
-
- /* Hook into the the CFRunLoop for the main thread */
-
- main_thread_run_loop = CFRunLoopGetCurrent ();
-
- observer = CFRunLoopObserverCreate (NULL, /* default allocator */
- kCFRunLoopAllActivities,
- true, /* repeats: not one-shot */
- 0, /* order (priority) */
- run_loop_observer_callback,
- NULL);
-
- CFRunLoopAddObserver (main_thread_run_loop, observer, kCFRunLoopCommonModes);
-
- /* Initialize our autorelease pool */
-
- autorelease_pool = [[NSAutoreleasePool alloc] init];
-}
+++ /dev/null
-/* gdkevents-quartz.c
- *
- * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
- * Copyright (C) 1998-2002 Tor Lillqvist
- * Copyright (C) 2005-2008 Imendio AB
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-#include <sys/types.h>
-#include <sys/sysctl.h>
-#include <pthread.h>
-#include <unistd.h>
-
-#import <Cocoa/Cocoa.h>
-#include <Carbon/Carbon.h>
-
-#include <gdk/gdkdisplayprivate.h>
-
-#include "gdkkeysyms.h"
-#include "gdkquartz.h"
-#include "gdkquartzdisplay.h"
-#include "gdkprivate-quartz.h"
-#include "gdkquartzdevicemanager-core.h"
-
-#define GRIP_WIDTH 15
-#define GRIP_HEIGHT 15
-#define GDK_LION_RESIZE 5
-
-#define SURFACE_IS_TOPLEVEL(window) TRUE
-
-/* This is the window corresponding to the key window */
-static GdkSurface *current_keyboard_window;
-
-
-static void append_event (GdkEvent *event,
- gboolean windowing);
-
-static GdkSurface *find_toplevel_under_pointer (GdkDisplay *display,
- NSPoint screen_point,
- gint *x,
- gint *y);
-
-
-static void
-gdk_quartz_ns_notification_callback (CFNotificationCenterRef center,
- void *observer,
- CFStringRef name,
- const void *object,
- CFDictionaryRef userInfo)
-{
- const char *setting = NULL;
-
- /* Translate name */
- if (CFStringCompare (name,
- CFSTR("AppleNoRedisplayAppearancePreferenceChanged"),
- 0) == kCFCompareEqualTo)
- setting = "gtk-primary-button-warps-slider";
-
- if (!setting)
- return;
-
- gdk_display_setting_changed (_gdk_display, setting);
-}
-
-static void
-gdk_quartz_events_init_notifications (void)
-{
- static gboolean notifications_initialized = FALSE;
-
- if (notifications_initialized)
- return;
- notifications_initialized = TRUE;
-
- /* Initialize any handlers for notifications we want to push to GTK
- * through GdkEventSettings.
- */
-
- /* This is an undocumented *distributed* notification to listen for changes
- * in scrollbar jump behavior. It is used by LibreOffice and WebKit as well.
- */
- CFNotificationCenterAddObserver (CFNotificationCenterGetDistributedCenter (),
- NULL,
- &gdk_quartz_ns_notification_callback,
- CFSTR ("AppleNoRedisplayAppearancePreferenceChanged"),
- NULL,
- CFNotificationSuspensionBehaviorDeliverImmediately);
-}
-
-void
-_gdk_quartz_events_init (void)
-{
- _gdk_quartz_event_loop_init ();
- gdk_quartz_events_init_notifications ();
-
- current_keyboard_window = g_object_ref (_gdk_root);
-}
-
-gboolean
-_gdk_quartz_display_has_pending (GdkDisplay *display)
-{
- return (_gdk_event_queue_find_first (display) ||
- (_gdk_quartz_event_loop_check_pending ()));
-}
-
-void
-_gdk_quartz_events_break_all_grabs (guint32 time)
-{
- GList *devices = NULL, *l;
- GdkSeat *seat;
-
- seat = gdk_display_get_default_seat (_gdk_display);
-
- devices = g_list_prepend (devices, gdk_seat_get_keyboard (seat));
- devices = g_list_prepend (devices, gdk_seat_get_pointer (seat));
-
- for (l = devices; l; l = l->next)
- {
- GdkDeviceGrabInfo *grab;
-
- grab = _gdk_display_get_last_device_grab (_gdk_display, l->data);
- if (grab)
- {
- grab->serial_end = 0;
- grab->implicit_ungrab = TRUE;
- }
-
- _gdk_display_device_grab_update (_gdk_display, l->data, NULL, 0);
- }
-
- g_list_free (devices);
-}
-
-static void
-fixup_event (GdkEvent *event)
-{
- if (event->any.surface)
- g_object_ref (event->any.surface);
- if (((event->any.type == GDK_ENTER_NOTIFY) ||
- (event->any.type == GDK_LEAVE_NOTIFY)) &&
- (event->crossing.child_window != NULL))
- g_object_ref (event->crossing.child_window);
- event->any.send_event = FALSE;
-}
-
-static void
-append_event (GdkEvent *event,
- gboolean windowing)
-{
- GList *node;
-
- fixup_event (event);
- node = _gdk_event_queue_append (_gdk_display, event);
-
- if (windowing)
- _gdk_windowing_got_event (_gdk_display, node, event, 0);
-}
-
-static gint
-gdk_event_apply_filters (NSEvent *nsevent,
- GdkEvent *event,
- GList **filters)
-{
- GList *tmp_list;
- GdkFilterReturn result;
-
- tmp_list = *filters;
-
- while (tmp_list)
- {
- GdkEventFilter *filter = (GdkEventFilter*) tmp_list->data;
- GList *node;
-
- if ((filter->flags & GDK_EVENT_FILTER_REMOVED) != 0)
- {
- tmp_list = tmp_list->next;
- continue;
- }
-
- filter->ref_count++;
- result = filter->function (nsevent, event, filter->data);
-
- /* get the next node after running the function since the
- function may add or remove a next node */
- node = tmp_list;
- tmp_list = tmp_list->next;
-
- filter->ref_count--;
- if (filter->ref_count == 0)
- {
- *filters = g_list_remove_link (*filters, node);
- g_list_free_1 (node);
- g_free (filter);
- }
-
- if (result != GDK_FILTER_CONTINUE)
- return result;
- }
-
- return GDK_FILTER_CONTINUE;
-}
-
-static guint32
-get_time_from_ns_event (NSEvent *event)
-{
- double time = [event timestamp];
-
- /* cast via double->uint64 conversion to make sure that it is
- * wrapped on 32-bit machines when it overflows
- */
- return (guint32) (guint64) (time * 1000.0);
-}
-
-static int
-get_mouse_button_from_ns_event (NSEvent *event)
-{
- NSInteger button;
-
- button = [event buttonNumber];
-
- switch (button)
- {
- case 0:
- return 1;
- case 1:
- return 3;
- case 2:
- return 2;
- default:
- return button + 1;
- }
-}
-
-static GdkModifierType
-get_mouse_button_modifiers_from_ns_buttons (NSUInteger nsbuttons)
-{
- GdkModifierType modifiers = 0;
-
- if (nsbuttons & (1 << 0))
- modifiers |= GDK_BUTTON1_MASK;
- if (nsbuttons & (1 << 1))
- modifiers |= GDK_BUTTON3_MASK;
- if (nsbuttons & (1 << 2))
- modifiers |= GDK_BUTTON2_MASK;
- if (nsbuttons & (1 << 3))
- modifiers |= GDK_BUTTON4_MASK;
- if (nsbuttons & (1 << 4))
- modifiers |= GDK_BUTTON5_MASK;
-
- return modifiers;
-}
-
-static GdkModifierType
-get_mouse_button_modifiers_from_ns_event (NSEvent *event)
-{
- int button;
- GdkModifierType state = 0;
-
- /* This maps buttons 1 to 5 to GDK_BUTTON[1-5]_MASK */
- button = get_mouse_button_from_ns_event (event);
- if (button >= 1 && button <= 5)
- state = (1 << (button + 7));
-
- return state;
-}
-
-static GdkModifierType
-get_keyboard_modifiers_from_ns_flags (NSUInteger nsflags)
-{
- GdkModifierType modifiers = 0;
-
- if (nsflags & NSAlphaShiftKeyMask)
- modifiers |= GDK_LOCK_MASK;
- if (nsflags & NSShiftKeyMask)
- modifiers |= GDK_SHIFT_MASK;
- if (nsflags & NSControlKeyMask)
- modifiers |= GDK_CONTROL_MASK;
- if (nsflags & NSAlternateKeyMask)
- modifiers |= GDK_ALT_MASK;
- if (nsflags & NSCommandKeyMask)
- modifiers |= GDK_MOD2_MASK;
-
- return modifiers;
-}
-
-static GdkModifierType
-get_keyboard_modifiers_from_ns_event (NSEvent *nsevent)
-{
- return get_keyboard_modifiers_from_ns_flags ([nsevent modifierFlags]);
-}
-
-/* Return an event mask from an NSEvent */
-static GdkEventMask
-get_event_mask_from_ns_event (NSEvent *nsevent)
-{
- switch ([nsevent type])
- {
- case NSLeftMouseDown:
- case NSRightMouseDown:
- case NSOtherMouseDown:
- return GDK_BUTTON_PRESS_MASK;
- case NSLeftMouseUp:
- case NSRightMouseUp:
- case NSOtherMouseUp:
- return GDK_BUTTON_RELEASE_MASK;
- case NSMouseMoved:
- return GDK_POINTER_MOTION_MASK;
- case NSScrollWheel:
- /* Since applications that want button press events can get
- * scroll events on X11 (since scroll wheel events are really
- * button press events there), we need to use GDK_BUTTON_PRESS_MASK too.
- */
- return GDK_SCROLL_MASK | GDK_BUTTON_PRESS_MASK;
- case NSLeftMouseDragged:
- return (GDK_POINTER_MOTION_MASK |
- GDK_BUTTON_MOTION_MASK | GDK_BUTTON1_MOTION_MASK |
- GDK_BUTTON1_MASK);
- case NSRightMouseDragged:
- return (GDK_POINTER_MOTION_MASK |
- GDK_BUTTON_MOTION_MASK | GDK_BUTTON3_MOTION_MASK |
- GDK_BUTTON3_MASK);
- case NSOtherMouseDragged:
- {
- GdkEventMask mask;
-
- mask = (GDK_POINTER_MOTION_MASK | GDK_BUTTON_MOTION_MASK);
-
- if (get_mouse_button_from_ns_event (nsevent) == 2)
- mask |= (GDK_BUTTON2_MOTION_MASK | GDK_BUTTON2_MOTION_MASK |
- GDK_BUTTON2_MASK);
-
- return mask;
- }
- case NSEventTypeMagnify:
- case NSEventTypeRotate:
- return GDK_TOUCHPAD_GESTURE_MASK;
- case NSKeyDown:
- case NSKeyUp:
- case NSFlagsChanged:
- {
- switch (_gdk_quartz_keys_event_type (nsevent))
- {
- case GDK_KEY_PRESS:
- return GDK_KEY_PRESS_MASK;
- case GDK_KEY_RELEASE:
- return GDK_KEY_RELEASE_MASK;
- case GDK_NOTHING:
- return 0;
- default:
- g_assert_not_reached ();
- }
- }
- break;
-
- case NSMouseEntered:
- return GDK_ENTER_NOTIFY_MASK;
-
- case NSMouseExited:
- return GDK_LEAVE_NOTIFY_MASK;
-
- default:
- g_assert_not_reached ();
- }
-
- return 0;
-}
-
-static void
-get_window_point_from_screen_point (GdkSurface *window,
- NSPoint screen_point,
- gint *x,
- gint *y)
-{
- NSPoint point;
- NSWindow *nswindow;
-
- nswindow = ((GdkSurfaceImplQuartz *)window->impl)->toplevel;
-
- point = [nswindow convertScreenToBase:screen_point];
-
- *x = point.x;
- *y = window->height - point.y;
-}
-
-static gboolean
-is_mouse_button_press_event (NSEventType type)
-{
- switch (type)
- {
- case NSLeftMouseDown:
- case NSRightMouseDown:
- case NSOtherMouseDown:
- return TRUE;
- }
-
- return FALSE;
-}
-
-static GdkSurface *
-get_toplevel_from_ns_event (NSEvent *nsevent,
- NSPoint *screen_point,
- gint *x,
- gint *y)
-{
- GdkSurface *toplevel = NULL;
-
- if ([nsevent window])
- {
- GdkQuartzView *view;
- NSPoint point, view_point;
- NSRect view_frame;
-
- view = (GdkQuartzView *)[[nsevent window] contentView];
-
- toplevel = [view gdkSurface];
-
- point = [nsevent locationInWindow];
- view_point = [view convertPoint:point fromView:nil];
- view_frame = [view frame];
-
- /* NSEvents come in with a window set, but with window coordinates
- * out of window bounds. For e.g. moved events this is fine, we use
- * this information to properly handle enter/leave notify and motion
- * events. For mouse button press/release, we want to avoid forwarding
- * these events however, because the window they relate to is not the
- * window set in the event. This situation appears to occur when button
- * presses come in just before (or just after?) a window is resized and
- * also when a button press occurs on the OS X window titlebar.
- *
- * By setting toplevel to NULL, we do another attempt to get the right
- * toplevel window below.
- */
- if (is_mouse_button_press_event ([nsevent type]) &&
- (view_point.x < view_frame.origin.x ||
- view_point.x >= view_frame.origin.x + view_frame.size.width ||
- view_point.y < view_frame.origin.y ||
- view_point.y >= view_frame.origin.y + view_frame.size.height))
- {
- toplevel = NULL;
-
- /* This is a hack for button presses to break all grabs. E.g. if
- * a menu is open and one clicks on the title bar (or anywhere
- * out of window bounds), we really want to pop down the menu (by
- * breaking the grabs) before OS X handles the action of the title
- * bar button.
- *
- * Because we cannot ingest this event into GDK, we have to do it
- * here, not very nice.
- */
- _gdk_quartz_events_break_all_grabs (get_time_from_ns_event (nsevent));
- }
- else
- {
- *screen_point = [[nsevent window] convertBaseToScreen:point];
-
- *x = point.x;
- *y = toplevel->height - point.y;
- }
- }
-
- if (!toplevel)
- {
- /* Fallback used when no NSWindow set. This happens e.g. when
- * we allow motion events without a window set in gdk_event_translate()
- * that occur immediately after the main menu bar was clicked/used.
- * This fallback will not return coordinates contained in a window's
- * titlebar.
- */
- *screen_point = [NSEvent mouseLocation];
- toplevel = find_toplevel_under_pointer (_gdk_display,
- *screen_point,
- x, y);
- }
-
- return toplevel;
-}
-
-static GdkEvent *
-create_focus_event (GdkSurface *window,
- gboolean in)
-{
- GdkEvent *event;
- GdkQuartzDeviceManagerCore *device_manager;
-
- event = gdk_event_new (GDK_FOCUS_CHANGE);
- event->focus_change.window = window;
- event->focus_change.in = in;
-
- device_manager = GDK_QUARTZ_DEVICE_MANAGER_CORE (_gdk_device_manager);
- gdk_event_set_device (event, device_manager->core_keyboard);
- gdk_event_set_seat (event, gdk_device_get_seat (device_manager->core_keyboard));
-
- return event;
-}
-
-
-static void
-generate_motion_event (GdkSurface *window)
-{
- NSPoint screen_point;
- GdkEvent *event;
- gint x, y, x_root, y_root;
- GdkQuartzDeviceManagerCore *device_manager;
-
- event = gdk_event_new (GDK_MOTION_NOTIFY);
- event->any.surface = NULL;
- event->any.send_event = TRUE;
-
- screen_point = [NSEvent mouseLocation];
-
- _gdk_quartz_surface_nspoint_to_gdk_xy (screen_point, &x_root, &y_root);
- get_window_point_from_screen_point (window, screen_point, &x, &y);
-
- event->any.type = GDK_MOTION_NOTIFY;
- event->motion.window = window;
- event->motion.time = get_time_from_ns_event ([NSApp currentEvent]);
- event->motion.x = x;
- event->motion.y = y;
- event->motion.x_root = x_root;
- event->motion.y_root = y_root;
- /* FIXME event->axes */
- event->motion.state = _gdk_quartz_events_get_current_keyboard_modifiers () |
- _gdk_quartz_events_get_current_mouse_modifiers ();
- device_manager = GDK_QUARTZ_DEVICE_MANAGER_CORE (_gdk_device_manager);
- event->motion.device = device_manager->core_pointer;
- gdk_event_set_seat (event, gdk_device_get_seat (device_manager->core_pointer));
-
- append_event (event, TRUE);
-}
-
-/* Note: Used to both set a new focus window and to unset the old one. */
-void
-_gdk_quartz_events_update_focus_window (GdkSurface *window,
- gboolean got_focus)
-{
- GdkEvent *event;
-
- if (got_focus && window == current_keyboard_window)
- return;
-
- /* FIXME: Don't do this when grabbed? Or make GdkQuartzNSWindow
- * disallow it in the first place instead?
- */
-
- if (!got_focus && window == current_keyboard_window)
- {
- event = create_focus_event (current_keyboard_window, FALSE);
- append_event (event, FALSE);
- g_object_unref (current_keyboard_window);
- current_keyboard_window = NULL;
- }
-
- if (got_focus)
- {
- if (current_keyboard_window)
- {
- event = create_focus_event (current_keyboard_window, FALSE);
- append_event (event, FALSE);
- g_object_unref (current_keyboard_window);
- current_keyboard_window = NULL;
- }
-
- event = create_focus_event (window, TRUE);
- append_event (event, FALSE);
- current_keyboard_window = g_object_ref (window);
-
- /* We just became the active window. Unlike X11, Mac OS X does
- * not send us motion events while the window does not have focus
- * ("is not key"). We send a dummy motion notify event now, so that
- * everything in the window is set to correct state.
- */
- generate_motion_event (window);
- }
-}
-
-void
-_gdk_quartz_events_send_map_event (GdkSurface *window)
-{
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (!impl->toplevel)
- return;
-
- if (window->event_mask & GDK_STRUCTURE_MASK)
- {
- GdkEvent event;
-
- event.any.type = GDK_MAP;
- event.any.surface = window;
-
- gdk_event_put (&event);
- }
-}
-
-static GdkSurface *
-find_toplevel_under_pointer (GdkDisplay *display,
- NSPoint screen_point,
- gint *x,
- gint *y)
-{
- GdkSurface *toplevel;
- GdkPointerSurfaceInfo *info;
-
- info = _gdk_display_get_pointer_info (display, GDK_QUARTZ_DEVICE_MANAGER_CORE (_gdk_device_manager)->core_pointer);
- toplevel = info->toplevel_under_pointer;
- if (toplevel && SURFACE_IS_TOPLEVEL (toplevel))
- get_window_point_from_screen_point (toplevel, screen_point, x, y);
-
- if (toplevel)
- {
- /* If the coordinates are out of window bounds, this toplevel is not
- * under the pointer and we thus return NULL. This can occur when
- * toplevel under pointer has not yet been updated due to a very recent
- * window resize. Alternatively, we should no longer be relying on
- * the toplevel_under_pointer value which is maintained in gdksurface.c.
- */
- if (*x < 0 || *y < 0 || *x >= toplevel->width || *y >= toplevel->height)
- return NULL;
- }
-
- return toplevel;
-}
-
-static GdkSurface *
-find_toplevel_for_keyboard_event (NSEvent *nsevent)
-{
- GList *devices = NULL, *l;
- GdkSurface *window;
- GdkDisplay *display;
- GdkQuartzView *view;
- GdkSeat *seat;
-
- view = (GdkQuartzView *)[[nsevent window] contentView];
- window = [view gdkSurface];
-
- display = gdk_surface_get_display (window);
-
- seat = gdk_display_get_default_seat (display);
-
- devices = g_list_prepend (devices, gdk_seat_get_keyboard (seat));
- devices = g_list_prepend (devices, gdk_seat_get_pointer (seat));
-
- for (l = devices; l; l = l->next)
- {
- GdkDeviceGrabInfo *grab;
- GdkDevice *device = l->data;
-
- if (gdk_device_get_source(device) != GDK_SOURCE_KEYBOARD)
- continue;
-
- grab = _gdk_display_get_last_device_grab (display, device);
- if (grab && grab->window && !grab->owner_events)
- {
- window = gdk_surface_get_toplevel (grab->window);
- break;
- }
- }
-
- g_list_free (devices);
-
- return window;
-}
-
-static GdkSurface *
-find_toplevel_for_mouse_event (NSEvent *nsevent,
- gint *x,
- gint *y)
-{
- NSPoint screen_point;
- NSEventType event_type;
- GdkSurface *toplevel;
- GdkDisplay *display;
- GdkDeviceGrabInfo *grab;
-
- toplevel = get_toplevel_from_ns_event (nsevent, &screen_point, x, y);
-
- display = gdk_surface_get_display (toplevel);
-
- event_type = [nsevent type];
-
- /* From the docs for XGrabPointer:
- *
- * If owner_events is True and if a generated pointer event
- * would normally be reported to this client, it is reported
- * as usual. Otherwise, the event is reported with respect to
- * the grab_window and is reported only if selected by
- * event_mask. For either value of owner_events, unreported
- * events are discarded.
- */
- grab = _gdk_display_get_last_device_grab (display,
- GDK_QUARTZ_DEVICE_MANAGER_CORE (_gdk_device_manager)->core_pointer);
- if (SURFACE_IS_TOPLEVEL (toplevel) && grab)
- {
- /* Implicit grabs do not go through XGrabPointer and thus the
- * event mask should not be checked.
- */
- if (!grab->implicit
- && (grab->event_mask & get_event_mask_from_ns_event (nsevent)) == 0)
- return NULL;
-
- if (grab->owner_events)
- {
- /* For owner events, we need to use the toplevel under the
- * pointer, not the window from the NSEvent, since that is
- * reported with respect to the key window, which could be
- * wrong.
- */
- GdkSurface *toplevel_under_pointer;
- gint x_tmp, y_tmp;
-
- toplevel_under_pointer = find_toplevel_under_pointer (display,
- screen_point,
- &x_tmp, &y_tmp);
- if (toplevel_under_pointer)
- {
- toplevel = toplevel_under_pointer;
- *x = x_tmp;
- *y = y_tmp;
- }
-
- return toplevel;
- }
- else
- {
- /* Finally check the grab window. */
- GdkSurface *grab_toplevel;
-
- grab_toplevel = gdk_surface_get_toplevel (grab->window);
- get_window_point_from_screen_point (grab_toplevel, screen_point,
- x, y);
-
- return grab_toplevel;
- }
-
- return NULL;
- }
- else
- {
- /* The non-grabbed case. */
- GdkSurface *toplevel_under_pointer;
- gint x_tmp, y_tmp;
-
- /* Ignore all events but mouse moved that might be on the title
- * bar (above the content view). The reason is that otherwise
- * gdk gets confused about getting e.g. button presses with no
- * window (the title bar is not known to it).
- */
- if (event_type != NSMouseMoved)
- if (*y < 0)
- return NULL;
-
- /* As for owner events, we need to use the toplevel under the
- * pointer, not the window from the NSEvent.
- */
- toplevel_under_pointer = find_toplevel_under_pointer (display,
- screen_point,
- &x_tmp, &y_tmp);
- if (toplevel_under_pointer
- && SURFACE_IS_TOPLEVEL (toplevel_under_pointer))
- {
- GdkSurfaceImplQuartz *toplevel_impl;
-
- toplevel = toplevel_under_pointer;
-
- toplevel_impl = (GdkSurfaceImplQuartz *)toplevel->impl;
-
- *x = x_tmp;
- *y = y_tmp;
- }
-
- return toplevel;
- }
-
- return NULL;
-}
-
-/* This function finds the correct window to send an event to, taking
- * into account grabs, event propagation, and event masks.
- */
-static GdkSurface *
-find_window_for_ns_event (NSEvent *nsevent,
- gint *x,
- gint *y,
- gint *x_root,
- gint *y_root)
-{
- GdkQuartzView *view;
- GdkSurface *toplevel;
- NSPoint screen_point;
- NSEventType event_type;
-
- view = (GdkQuartzView *)[[nsevent window] contentView];
-
- toplevel = get_toplevel_from_ns_event (nsevent, &screen_point, x, y);
- if (!toplevel)
- return NULL;
- _gdk_quartz_surface_nspoint_to_gdk_xy (screen_point, x_root, y_root);
-
- event_type = [nsevent type];
-
- switch (event_type)
- {
- case NSLeftMouseDown:
- case NSRightMouseDown:
- case NSOtherMouseDown:
- case NSLeftMouseUp:
- case NSRightMouseUp:
- case NSOtherMouseUp:
- case NSMouseMoved:
- case NSScrollWheel:
- case NSLeftMouseDragged:
- case NSRightMouseDragged:
- case NSOtherMouseDragged:
- case NSEventTypeMagnify:
- case NSEventTypeRotate:
- return find_toplevel_for_mouse_event (nsevent, x, y);
-
- case NSMouseEntered:
- case NSMouseExited:
- /* Only handle our own entered/exited events, not the ones for the
- * titlebar buttons.
- */
- if ([view trackingRect] == [nsevent trackingNumber])
- return toplevel;
- else
- return NULL;
-
- case NSKeyDown:
- case NSKeyUp:
- case NSFlagsChanged:
- return find_toplevel_for_keyboard_event (nsevent);
-
- default:
- /* Ignore everything else. */
- break;
- }
-
- return NULL;
-}
-
-static void
-fill_crossing_event (GdkSurface *toplevel,
- GdkEvent *event,
- NSEvent *nsevent,
- gint x,
- gint y,
- gint x_root,
- gint y_root,
- GdkEventType event_type,
- GdkCrossingMode mode,
- GdkNotifyType detail)
-{
- GdkQuartzDeviceManagerCore *device_manager;
-
- event->any.type = event_type;
- event->crossing.window = toplevel;
- event->crossing.child_window = NULL;
- event->crossing.time = get_time_from_ns_event (nsevent);
- event->crossing.x = x;
- event->crossing.y = y;
- event->crossing.x_root = x_root;
- event->crossing.y_root = y_root;
- event->crossing.mode = mode;
- event->crossing.detail = detail;
- event->crossing.state = get_keyboard_modifiers_from_ns_event (nsevent) |
- _gdk_quartz_events_get_current_mouse_modifiers ();
-
- device_manager = GDK_QUARTZ_DEVICE_MANAGER_CORE (_gdk_device_manager);
- gdk_event_set_device (event, device_manager->core_pointer);
- gdk_event_set_seat (event, gdk_device_get_seat (device_manager->core_pointer));
-
- /* FIXME: Focus and button state? */
-}
-
-/* fill_pinch_event handles the conversion from the two OSX gesture events
- NSEventTypeMagnfiy and NSEventTypeRotate to the GDK_TOUCHPAD_PINCH event.
- The normal behavior of the OSX events is that they produce as sequence of
- 1 x NSEventPhaseBegan,
- n x NSEventPhaseChanged,
- 1 x NSEventPhaseEnded
- This can happen for both the Magnify and the Rotate events independently.
- As both events are summarized in one GDK_TOUCHPAD_PINCH event sequence, a
- little state machine handles the case of two NSEventPhaseBegan events in
- a sequence, e.g. Magnify(Began), Magnify(Changed)..., Rotate(Began)...
- such that PINCH(STARTED), PINCH(UPDATE).... will not show a second
- PINCH(STARTED) event.
-*/
-#ifdef AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER
-static void
-fill_pinch_event (GdkSurface *window,
- GdkEvent *event,
- NSEvent *nsevent,
- gint x,
- gint y,
- gint x_root,
- gint y_root)
-{
- static double last_scale = 1.0;
- static enum {
- FP_STATE_IDLE,
- FP_STATE_UPDATE
- } last_state = FP_STATE_IDLE;
- GdkQuartzDeviceManagerCore *device_manager;
-
- device_manager = GDK_QUARTZ_DEVICE_MANAGER_CORE (_gdk_device_manager);
-
- event->any.type = GDK_TOUCHPAD_PINCH;
- event->touchpad_pinch.window = window;
- event->touchpad_pinch.time = get_time_from_ns_event (nsevent);
- event->touchpad_pinch.x = x;
- event->touchpad_pinch.y = y;
- event->touchpad_pinch.x_root = x_root;
- event->touchpad_pinch.y_root = y_root;
- event->touchpad_pinch.state = get_keyboard_modifiers_from_ns_event (nsevent);
- event->touchpad_pinch.n_fingers = 2;
- event->touchpad_pinch.dx = 0.0;
- event->touchpad_pinch.dy = 0.0;
- gdk_event_set_device (event, device_manager->core_pointer);
-
- switch ([nsevent phase])
- {
- case NSEventPhaseBegan:
- switch (last_state)
- {
- case FP_STATE_IDLE:
- event->touchpad_pinch.phase = GDK_TOUCHPAD_GESTURE_PHASE_BEGIN;
- last_state = FP_STATE_UPDATE;
- last_scale = 1.0;
- break;
- case FP_STATE_UPDATE:
- /* We have already received a PhaseBegan event but no PhaseEnded
- event. This can happen, e.g. Magnify(Began), Magnify(Change)...
- Rotate(Began), Rotate (Change),...., Magnify(End) Rotate(End)
- */
- event->touchpad_pinch.phase = GDK_TOUCHPAD_GESTURE_PHASE_UPDATE;
- break;
- }
- break;
- case NSEventPhaseChanged:
- event->touchpad_pinch.phase = GDK_TOUCHPAD_GESTURE_PHASE_UPDATE;
- break;
- case NSEventPhaseEnded:
- event->touchpad_pinch.phase = GDK_TOUCHPAD_GESTURE_PHASE_END;
- switch (last_state)
- {
- case FP_STATE_IDLE:
- /* We are idle but have received a second PhaseEnded event.
- This can happen because we have Magnify and Rotate OSX
- event sequences. We just send a second end GDK_PHASE_END.
- */
- break;
- case FP_STATE_UPDATE:
- last_state = FP_STATE_IDLE;
- break;
- }
- break;
- case NSEventPhaseCancelled:
- event->touchpad_pinch.phase = GDK_TOUCHPAD_GESTURE_PHASE_CANCEL;
- last_state = FP_STATE_IDLE;
- break;
- case NSEventPhaseMayBegin:
- case NSEventPhaseStationary:
- event->touchpad_pinch.phase = GDK_TOUCHPAD_GESTURE_PHASE_CANCEL;
- break;
- default:
- g_assert_not_reached ();
- break;
- }
-
- switch ([nsevent type])
- {
- case NSEventTypeMagnify:
- last_scale *= [nsevent magnification] + 1.0;
- event->touchpad_pinch.angle_delta = 0.0;
- break;
- case NSEventTypeRotate:
- event->touchpad_pinch.angle_delta = - [nsevent rotation] * G_PI / 180.0;
- break;
- default:
- g_assert_not_reached ();
- }
- event->touchpad_pinch.scale = last_scale;
-}
-#endif /* OSX Version >= 10.8 */
-
-static void
-fill_button_event (GdkSurface *window,
- GdkEvent *event,
- NSEvent *nsevent,
- gint x,
- gint y,
- gint x_root,
- gint y_root)
-{
- GdkEventType type;
- gint state;
- GdkQuartzDeviceManagerCore *device_manager;
-
- state = get_keyboard_modifiers_from_ns_event (nsevent) |
- _gdk_quartz_events_get_current_mouse_modifiers ();
-
- switch ([nsevent type])
- {
- case NSLeftMouseDown:
- case NSRightMouseDown:
- case NSOtherMouseDown:
- type = GDK_BUTTON_PRESS;
- state &= ~get_mouse_button_modifiers_from_ns_event (nsevent);
- break;
-
- case NSLeftMouseUp:
- case NSRightMouseUp:
- case NSOtherMouseUp:
- type = GDK_BUTTON_RELEASE;
- state |= get_mouse_button_modifiers_from_ns_event (nsevent);
- break;
-
- default:
- g_assert_not_reached ();
- }
-
- event->any.type = type;
- event->button.window = window;
- event->button.time = get_time_from_ns_event (nsevent);
- event->button.x = x;
- event->button.y = y;
- event->button.x_root = x_root;
- event->button.y_root = y_root;
- /* FIXME event->axes */
- event->button.state = state;
- event->button.button = get_mouse_button_from_ns_event (nsevent);
- device_manager = GDK_QUARTZ_DEVICE_MANAGER_CORE (_gdk_device_manager);
- event->button.device = device_manager->core_pointer;
- gdk_event_set_seat (event, gdk_device_get_seat (device_manager->core_pointer));
-}
-
-static void
-fill_motion_event (GdkSurface *window,
- GdkEvent *event,
- NSEvent *nsevent,
- gint x,
- gint y,
- gint x_root,
- gint y_root)
-{
- GdkQuartzDeviceManagerCore *device_manager;
-
- event->any.type = GDK_MOTION_NOTIFY;
- event->motion.window = window;
- event->motion.time = get_time_from_ns_event (nsevent);
- event->motion.x = x;
- event->motion.y = y;
- event->motion.x_root = x_root;
- event->motion.y_root = y_root;
- /* FIXME event->axes */
- event->motion.state = get_keyboard_modifiers_from_ns_event (nsevent) |
- _gdk_quartz_events_get_current_mouse_modifiers ();
- device_manager = GDK_QUARTZ_DEVICE_MANAGER_CORE (_gdk_device_manager);
- event->motion.device = device_manager->core_pointer;
- gdk_event_set_seat (event, gdk_device_get_seat (device_manager->core_pointer));
-}
-
-static void
-fill_scroll_event (GdkSurface *window,
- GdkEvent *event,
- NSEvent *nsevent,
- gint x,
- gint y,
- gint x_root,
- gint y_root,
- gdouble delta_x,
- gdouble delta_y,
- GdkScrollDirection direction)
-{
- GdkQuartzDeviceManagerCore *device_manager;
- NSPoint point;
-
- point = [nsevent locationInWindow];
- device_manager = GDK_QUARTZ_DEVICE_MANAGER_CORE (_gdk_device_manager);
-
- event->any.type = GDK_SCROLL;
- event->scroll.window = window;
- event->scroll.time = get_time_from_ns_event (nsevent);
- event->scroll.x = x;
- event->scroll.y = y;
- event->scroll.x_root = x_root;
- event->scroll.y_root = y_root;
- event->scroll.state = get_keyboard_modifiers_from_ns_event (nsevent);
- event->scroll.direction = direction;
- event->scroll.device = device_manager->core_pointer;
- event->scroll.delta_x = delta_x;
- event->scroll.delta_y = delta_y;
- gdk_event_set_seat (event, gdk_device_get_seat (device_manager->core_pointer));
-}
-
-static void
-fill_key_event (GdkSurface *window,
- GdkEvent *event,
- NSEvent *nsevent,
- GdkEventType type)
-{
- GdkEventPrivate *priv;
- GdkQuartzDeviceManagerCore *device_manager;
-
- priv = (GdkEventPrivate *) event;
- priv->windowing_data = [nsevent retain];
-
- event->any.type = type;
- event->key.window = window;
- event->key.time = get_time_from_ns_event (nsevent);
- event->key.state = get_keyboard_modifiers_from_ns_event (nsevent);
- event->key.hardware_keycode = [nsevent keyCode];
- gdk_event_set_scancode (event, [nsevent keyCode]);
- event->key.group = ([nsevent modifierFlags] & NSAlternateKeyMask) ? 1 : 0;
- event->key.keyval = GDK_KEY_VoidSymbol;
-
- device_manager = GDK_QUARTZ_DEVICE_MANAGER_CORE (_gdk_device_manager);
- gdk_event_set_device (event, device_manager->core_keyboard);
- gdk_event_set_seat (event, gdk_device_get_seat (device_manager->core_keyboard));
-
- gdk_keymap_translate_keyboard_state (gdk_display_get_keymap (_gdk_display),
- event->key.hardware_keycode,
- event->key.state,
- event->key.group,
- &event->key.keyval,
- NULL, NULL, NULL);
-
- event->key.is_modifier = _gdk_quartz_keys_is_modifier (event->key.hardware_keycode);
-
- /* If the key press is a modifier, the state should include the mask
- * for that modifier but only for releases, not presses. This
- * matches the X11 backend behavior.
- */
- if (event->key.is_modifier)
- {
- int mask = 0;
-
- switch (event->key.keyval)
- {
- case GDK_KEY_Meta_R:
- case GDK_KEY_Meta_L:
- mask = GDK_MOD2_MASK;
- break;
- case GDK_KEY_Shift_R:
- case GDK_KEY_Shift_L:
- mask = GDK_SHIFT_MASK;
- break;
- case GDK_KEY_Caps_Lock:
- mask = GDK_LOCK_MASK;
- break;
- case GDK_KEY_Alt_R:
- case GDK_KEY_Alt_L:
- mask = GDK_ALT_MASK;
- break;
- case GDK_KEY_Control_R:
- case GDK_KEY_Control_L:
- mask = GDK_CONTROL_MASK;
- break;
- default:
- mask = 0;
- }
-
- if (type == GDK_KEY_PRESS)
- event->key.state &= ~mask;
- else if (type == GDK_KEY_RELEASE)
- event->key.state |= mask;
- }
-
- event->key.state |= _gdk_quartz_events_get_current_mouse_modifiers ();
-
- /* The X11 backend adds the first virtual modifier MOD2..MOD5 are
- * mapped to. Since we only have one virtual modifier in the quartz
- * backend, calling the standard function will do.
- */
- gdk_keymap_add_virtual_modifiers (gdk_display_get_keymap (_gdk_display),
- &event->key.state);
-
- GDK_NOTE(EVENTS,
- g_message ("key %s:\t\twindow: %p key: %12s %d",
- type == GDK_KEY_PRESS ? "press" : "release",
- event->key.window,
- event->key.keyval ? gdk_keyval_name (event->key.keyval) : "(none)",
- event->key.keyval));
-}
-
-static gboolean
-synthesize_crossing_event (GdkSurface *window,
- GdkEvent *event,
- NSEvent *nsevent,
- gint x,
- gint y,
- gint x_root,
- gint y_root)
-{
- switch ([nsevent type])
- {
- case NSMouseEntered:
- /* Enter events are considered always to be from another toplevel
- * window, this shouldn't negatively affect any app or gtk code,
- * and is the only way to make GtkMenu work. EEK EEK EEK.
- */
- if (!(window->event_mask & GDK_ENTER_NOTIFY_MASK))
- return FALSE;
-
- fill_crossing_event (window, event, nsevent,
- x, y,
- x_root, y_root,
- GDK_ENTER_NOTIFY,
- GDK_CROSSING_NORMAL,
- GDK_NOTIFY_NONLINEAR);
- return TRUE;
-
- case NSMouseExited:
- /* See above */
- if (!(window->event_mask & GDK_LEAVE_NOTIFY_MASK))
- return FALSE;
-
- fill_crossing_event (window, event, nsevent,
- x, y,
- x_root, y_root,
- GDK_LEAVE_NOTIFY,
- GDK_CROSSING_NORMAL,
- GDK_NOTIFY_NONLINEAR);
- return TRUE;
-
- default:
- break;
- }
-
- return FALSE;
-}
-
-void
-_gdk_quartz_synthesize_null_key_event (GdkSurface *window)
-{
- GdkEvent *event;
- GdkQuartzDeviceManagerCore *device_manager;
-
- event = gdk_event_new (GDK_KEY_PRESS);
- event->any.type = GDK_KEY_PRESS;
- event->key.window = window;
- event->key.state = 0;
- event->key.hardware_keycode = 0;
- event->key.group = 0;
- event->key.keyval = GDK_KEY_VoidSymbol;
- device_manager = GDK_QUARTZ_DEVICE_MANAGER_CORE (_gdk_device_manager);
- gdk_event_set_device (event, device_manager->core_keyboard);
- gdk_event_set_seat (event, gdk_device_get_seat (device_manager->core_keyboard));
- append_event(event, FALSE);
-}
-
-GdkModifierType
-_gdk_quartz_events_get_current_keyboard_modifiers (void)
-{
- if (gdk_quartz_osx_version () >= GDK_OSX_SNOW_LEOPARD)
- {
- return get_keyboard_modifiers_from_ns_flags ([NSClassFromString(@"NSEvent") modifierFlags]);
- }
- else
- {
- guint carbon_modifiers = GetCurrentKeyModifiers ();
- GdkModifierType modifiers = 0;
-
- if (carbon_modifiers & alphaLock)
- modifiers |= GDK_LOCK_MASK;
- if (carbon_modifiers & shiftKey)
- modifiers |= GDK_SHIFT_MASK;
- if (carbon_modifiers & controlKey)
- modifiers |= GDK_CONTROL_MASK;
- if (carbon_modifiers & optionKey)
- modifiers |= GDK_ALT_MASK;
- if (carbon_modifiers & cmdKey)
- modifiers |= GDK_MOD2_MASK;
-
- return modifiers;
- }
-}
-
-GdkModifierType
-_gdk_quartz_events_get_current_mouse_modifiers (void)
-{
- if (gdk_quartz_osx_version () >= GDK_OSX_SNOW_LEOPARD)
- {
- return get_mouse_button_modifiers_from_ns_buttons ([NSClassFromString(@"NSEvent") pressedMouseButtons]);
- }
- else
- {
- return get_mouse_button_modifiers_from_ns_buttons (GetCurrentButtonState ());
- }
-}
-
-/* Detect window resizing */
-
-static gboolean
-test_resize (NSEvent *event, GdkSurface *toplevel, gint x, gint y)
-{
- GdkSurfaceImplQuartz *toplevel_impl;
- gboolean lion;
-
- /* Resizing from the resize indicator only begins if an NSLeftMouseButton
- * event is received in the resizing area.
- */
- toplevel_impl = (GdkSurfaceImplQuartz *)toplevel->impl;
- if ([toplevel_impl->toplevel showsResizeIndicator])
- if ([event type] == NSLeftMouseDown &&
- [toplevel_impl->toplevel showsResizeIndicator])
- {
- NSRect frame;
-
- /* If the resize indicator is visible and the event
- * is in the lower right 15x15 corner, we leave these
- * events to Cocoa as to be handled as resize events.
- * Applications may have widgets in this area. These
- * will most likely be larger than 15x15 and for
- * scroll bars there are also other means to move
- * the scroll bar. Since the resize indicator is
- * the only way of resizing windows on Mac OS, it
- * is too important to not make functional.
- */
- frame = [toplevel_impl->view bounds];
- if (x > frame.size.width - GRIP_WIDTH &&
- x < frame.size.width &&
- y > frame.size.height - GRIP_HEIGHT &&
- y < frame.size.height)
- return TRUE;
- }
-
- /* If we're on Lion and within 5 pixels of an edge,
- * then assume that the user wants to resize, and
- * return NULL to let Quartz get on with it. We check
- * the selector isRestorable to see if we're on 10.7.
- * This extra check is in case the user starts
- * dragging before GDK recognizes the grab.
- *
- * We perform this check for a button press of all buttons, because we
- * do receive, for instance, a right mouse down event for a GDK surface
- * for x-coordinate range [-3, 0], but we do not want to forward this
- * into GDK. Forwarding such events into GDK will confuse the pointer
- * window finding code, because there are no GdkSurfaces present in
- * the range [-3, 0].
- */
- lion = gdk_quartz_osx_version () >= GDK_OSX_LION;
- if (lion &&
- ([event type] == NSLeftMouseDown ||
- [event type] == NSRightMouseDown ||
- [event type] == NSOtherMouseDown))
- {
- if (x < GDK_LION_RESIZE ||
- x > toplevel->width - GDK_LION_RESIZE ||
- y > toplevel->height - GDK_LION_RESIZE)
- return TRUE;
- }
-
- return FALSE;
-}
-
-static gboolean
-gdk_event_translate (GdkEvent *event,
- NSEvent *nsevent)
-{
- NSEventType event_type;
- NSWindow *nswindow;
- GdkSurface *window;
- int x, y;
- int x_root, y_root;
- gboolean return_val;
-
- /* There is no support for real desktop wide grabs, so we break
- * grabs when the application loses focus (gets deactivated).
- */
- event_type = [nsevent type];
- if (event_type == NSAppKitDefined)
- {
- if ([nsevent subtype] == NSApplicationDeactivatedEventType)
- _gdk_quartz_events_break_all_grabs (get_time_from_ns_event (nsevent));
-
- /* This could potentially be used to break grabs when clicking
- * on the title. The subtype 20 is undocumented so it's probably
- * not a good idea: else if (subtype == 20) break_all_grabs ();
- */
-
- /* Leave all AppKit events to AppKit. */
- return FALSE;
- }
-
- if (_gdk_default_filters)
- {
- /* Apply global filters */
- GdkFilterReturn result;
-
- result = gdk_event_apply_filters (nsevent, event, &_gdk_default_filters);
- if (result != GDK_FILTER_CONTINUE)
- {
- return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
- goto done;
- }
- }
-
- nswindow = [nsevent window];
-
- /* Ignore events for windows not created by GDK. */
- if (nswindow && ![[nswindow contentView] isKindOfClass:[GdkQuartzView class]])
- return FALSE;
-
- /* Ignore events for ones with no windows */
- if (!nswindow)
- {
- GdkSurface *toplevel = NULL;
-
- if (event_type == NSMouseMoved)
- {
- /* Motion events received after clicking the menu bar do not have the
- * window field set. Instead of giving up on the event immediately,
- * we first check whether this event is within our window bounds.
- */
- NSPoint screen_point = [NSEvent mouseLocation];
- gint x_tmp, y_tmp;
-
- toplevel = find_toplevel_under_pointer (_gdk_display,
- screen_point,
- &x_tmp, &y_tmp);
- }
-
- if (!toplevel)
- return FALSE;
- }
-
- /* Ignore events and break grabs while the window is being
- * dragged. This is a workaround for the window getting events for
- * the window title.
- */
- if ([(GdkQuartzNSWindow *)nswindow isInMove])
- {
- _gdk_quartz_events_break_all_grabs (get_time_from_ns_event (nsevent));
- return FALSE;
- }
-
- /* Also when in a manual resize or move , we ignore events so that
- * these are pushed to GdkQuartzNSWindow's sendEvent handler.
- */
- if ([(GdkQuartzNSWindow *)nswindow isInManualResizeOrMove])
- return FALSE;
-
- /* Find the right GDK surface to send the event to, taking grabs and
- * event masks into consideration.
- */
- window = find_window_for_ns_event (nsevent, &x, &y, &x_root, &y_root);
- if (!window)
- return FALSE;
-
- /* Quartz handles resizing on its own, so we want to stay out of the way. */
- if (test_resize (nsevent, window, x, y))
- return FALSE;
-
- /* Apply any window filters. */
- if (GDK_IS_SURFACE (window))
- {
- GdkFilterReturn result;
-
- if (window->filters)
- {
- g_object_ref (window);
-
- result = gdk_event_apply_filters (nsevent, event, &window->filters);
-
- g_object_unref (window);
-
- if (result != GDK_FILTER_CONTINUE)
- {
- return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
- goto done;
- }
- }
- }
-
- /* If the app is not active leave the event to AppKit so the window gets
- * focused correctly and don't do click-through (so we behave like most
- * native apps). If the app is active, we focus the window and then handle
- * the event, also to match native apps.
- */
- if ((event_type == NSRightMouseDown ||
- event_type == NSOtherMouseDown ||
- event_type == NSLeftMouseDown))
- {
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (![NSApp isActive])
- {
- [NSApp activateIgnoringOtherApps:YES];
- return FALSE;
- }
- else if (![impl->toplevel isKeyWindow])
- {
- GdkDeviceGrabInfo *grab;
-
- grab = _gdk_display_get_last_device_grab (_gdk_display,
- GDK_QUARTZ_DEVICE_MANAGER_CORE (_gdk_device_manager)->core_pointer);
- if (!grab)
- [impl->toplevel makeKeyWindow];
- }
- }
-
- return_val = TRUE;
-
- switch (event_type)
- {
- case NSLeftMouseDown:
- case NSRightMouseDown:
- case NSOtherMouseDown:
- case NSLeftMouseUp:
- case NSRightMouseUp:
- case NSOtherMouseUp:
- fill_button_event (window, event, nsevent, x, y, x_root, y_root);
- break;
-
- case NSLeftMouseDragged:
- case NSRightMouseDragged:
- case NSOtherMouseDragged:
- case NSMouseMoved:
- fill_motion_event (window, event, nsevent, x, y, x_root, y_root);
- break;
-
- case NSScrollWheel:
- {
- GdkScrollDirection direction;
- float dx;
- float dy;
-#ifdef AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
- if (gdk_quartz_osx_version() >= GDK_OSX_LION &&
- [nsevent hasPreciseScrollingDeltas])
- {
- dx = [nsevent scrollingDeltaX];
- dy = [nsevent scrollingDeltaY];
- direction = GDK_SCROLL_SMOOTH;
-
- fill_scroll_event (window, event, nsevent, x, y, x_root, y_root,
- -dx, -dy, direction);
-
- /* Fall through for scroll buttons emulation */
- }
-#endif
- dx = [nsevent deltaX];
- dy = [nsevent deltaY];
-
- if (dy != 0.0)
- {
- if (dy < 0.0)
- direction = GDK_SCROLL_DOWN;
- else
- direction = GDK_SCROLL_UP;
-
- dy = fabs (dy);
- dx = 0.0;
- }
- else if (dx != 0.0)
- {
- if (dx < 0.0)
- direction = GDK_SCROLL_RIGHT;
- else
- direction = GDK_SCROLL_LEFT;
-
- dx = fabs (dx);
- dy = 0.0;
- }
-
- if (dx != 0.0 || dy != 0.0)
- {
-#ifdef AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
- if (gdk_quartz_osx_version() >= GDK_OSX_LION &&
- [nsevent hasPreciseScrollingDeltas])
- {
- GdkEvent *emulated_event;
-
- emulated_event = gdk_event_new (GDK_SCROLL);
- gdk_event_set_pointer_emulated (emulated_event, TRUE);
- fill_scroll_event (window, emulated_event, nsevent,
- x, y, x_root, y_root,
- dx, dy, direction);
- append_event (emulated_event, TRUE);
- }
- else
-#endif
- fill_scroll_event (window, event, nsevent,
- x, y, x_root, y_root,
- dx, dy, direction);
- }
- }
- break;
-#ifdef AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER
- case NSEventTypeMagnify:
- case NSEventTypeRotate:
- /* Event handling requires [NSEvent phase] which was introduced in 10.7 */
- /* However - Tests on 10.7 showed that phase property does not work */
- if (gdk_quartz_osx_version () >= GDK_OSX_MOUNTAIN_LION)
- fill_pinch_event (window, event, nsevent, x, y, x_root, y_root);
- else
- return_val = FALSE;
- break;
-#endif
- case NSMouseExited:
- if (SURFACE_IS_TOPLEVEL (window))
- [[NSCursor arrowCursor] set];
- /* fall through */
- case NSMouseEntered:
- return_val = synthesize_crossing_event (window, event, nsevent, x, y, x_root, y_root);
- break;
-
- case NSKeyDown:
- case NSKeyUp:
- case NSFlagsChanged:
- {
- GdkEventType type;
-
- type = _gdk_quartz_keys_event_type (nsevent);
- if (type == GDK_NOTHING)
- return_val = FALSE;
- else
- fill_key_event (window, event, nsevent, type);
- }
- break;
-
- default:
- /* Ignore everything elsee. */
- return_val = FALSE;
- break;
- }
-
- done:
- if (return_val)
- {
- if (event->any.surface)
- g_object_ref (event->any.surface);
- if (((event->any.type == GDK_ENTER_NOTIFY) ||
- (event->any.type == GDK_LEAVE_NOTIFY)) &&
- (event->crossing.child_window != NULL))
- g_object_ref (event->crossing.child_window);
- }
- else
- {
- /* Mark this event as having no resources to be freed */
- event->any.surface = NULL;
- event->any.type = GDK_NOTHING;
- }
-
- return return_val;
-}
-
-void
-_gdk_quartz_display_queue_events (GdkDisplay *display)
-{
- NSEvent *nsevent;
-
- nsevent = _gdk_quartz_event_loop_get_pending ();
- if (nsevent)
- {
- GdkEvent *event;
- GList *node;
-
- event = gdk_event_new (GDK_NOTHING);
-
- event->any.surface = NULL;
- event->any.send_event = FALSE;
-
- ((GdkEventPrivate *)event)->flags |= GDK_EVENT_PENDING;
-
- node = _gdk_event_queue_append (display, event);
-
- if (gdk_event_translate (event, nsevent))
- {
- ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING;
- _gdk_windowing_got_event (display, node, event, 0);
- }
- else
- {
- _gdk_event_queue_remove_link (display, node);
- g_list_free_1 (node);
- g_object_unref (event);
-
- [NSApp sendEvent:nsevent];
- }
-
- _gdk_quartz_event_loop_release_event (nsevent);
- }
-}
-
-gboolean
-_gdk_quartz_get_setting (const gchar *name,
- GValue *value)
-{
- if (strcmp (name, "gtk-double-click-time") == 0)
- {
- NSUserDefaults *defaults;
- float t;
-
- GDK_QUARTZ_ALLOC_POOL;
-
- defaults = [NSUserDefaults standardUserDefaults];
-
- t = [defaults floatForKey:@"com.apple.mouse.doubleClickThreshold"];
- if (t == 0.0)
- {
- /* No user setting, use the default in OS X. */
- t = 0.5;
- }
-
- GDK_QUARTZ_RELEASE_POOL;
-
- g_value_set_int (value, t * 1000);
-
- return TRUE;
- }
- else if (strcmp (name, "gtk-font-name") == 0)
- {
- NSString *name;
- char *str;
- gint size;
-
- GDK_QUARTZ_ALLOC_POOL;
-
- name = [[NSFont systemFontOfSize:0] familyName];
- size = (gint)[[NSFont userFontOfSize:0] pointSize];
-
- /* Let's try to use the "views" font size (12pt) by default. This is
- * used for lists/text/other "content" which is the largest parts of
- * apps, using the "regular control" size (13pt) looks a bit out of
- * place. We might have to tweak this.
- */
-
- /* The size has to be hardcoded as there doesn't seem to be a way to
- * get the views font size programmatically.
- */
- str = g_strdup_printf ("%s %d", [name UTF8String], size);
- g_value_set_string (value, str);
- g_free (str);
-
- GDK_QUARTZ_RELEASE_POOL;
-
- return TRUE;
- }
- else if (strcmp (name, "gtk-primary-button-warps-slider") == 0)
- {
- GDK_QUARTZ_ALLOC_POOL;
-
- BOOL setting = [[NSUserDefaults standardUserDefaults] boolForKey:@"AppleScrollerPagingBehavior"];
-
- /* If the Apple property is YES, it means "warp" */
- g_value_set_boolean (value, setting == YES);
-
- GDK_QUARTZ_RELEASE_POOL;
-
- return TRUE;
- }
- else if (strcmp (name, "gtk-shell-shows-desktop") == 0)
- {
- GDK_QUARTZ_ALLOC_POOL;
-
- g_value_set_boolean (value, TRUE);
-
- GDK_QUARTZ_RELEASE_POOL;
-
- return TRUE;
- }
-
- /* FIXME: Add more settings */
-
- return FALSE;
-}
-
-void
-_gdk_quartz_display_event_data_copy (GdkDisplay *display,
- const GdkEvent *src,
- GdkEvent *dst)
-{
- GdkEventPrivate *priv_src = (GdkEventPrivate *) src;
- GdkEventPrivate *priv_dst = (GdkEventPrivate *) dst;
-
- if (priv_src->windowing_data)
- {
- priv_dst->windowing_data = priv_src->windowing_data;
- [(NSEvent *)priv_dst->windowing_data retain];
- }
-}
-
-void
-_gdk_quartz_display_event_data_free (GdkDisplay *display,
- GdkEvent *event)
-{
- GdkEventPrivate *priv = (GdkEventPrivate *) event;
-
- if (priv->windowing_data)
- {
- [(NSEvent *)priv->windowing_data release];
- priv->windowing_data = NULL;
- }
-}
+++ /dev/null
-/* GDK - The GIMP Drawing Kit
- *
- * gdkglcontext-quartz.c: Quartz specific OpenGL wrappers
- *
- * Copyright © 2014 Emmanuele Bassi
- * Copyright © 2014 Alexander Larsson
- * Copyright © 2014 Brion Vibber
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-
-#include "gdkglcontext-quartz.h"
-
-#include "gdkintl.h"
-
-GdkGLContext *
-gdk_quartz_surface_create_gl_context (GdkSurface *window,
- gboolean attached,
- GdkGLContext *share,
- GError **error)
-{
- /* FIXME: implement */
- g_set_error_literal (error, GDK_GL_ERROR, GDK_GL_ERROR_NOT_AVAILABLE,
- _("Not implemented on OS X"));
- return NULL;
-}
+++ /dev/null
-/* GDK - The GIMP Drawing Kit
- *
- * gdkglcontext-quartz.h: Private Quartz specific OpenGL wrappers
- *
- * Copyright © 2014 Emmanuele Bassi
- * Copyright © 2014 Red Hat, Int
- * Copyright © 2014 Brion Vibber
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __GDK_QUARTZ_GL_CONTEXT__
-#define __GDK_QUARTZ_GL_CONTEXT__
-
-#include "gdkglcontextprivate.h"
-#include "gdksurface.h"
-#include "gdkinternals.h"
-
-G_BEGIN_DECLS
-
-GdkGLContext * gdk_quartz_surface_create_gl_context (GdkSurface *window,
- gboolean attach,
- GdkGLContext *share,
- GError **error);
-
-G_END_DECLS
-
-#endif /* __GDK_QUARTZ_GL_CONTEXT__ */
+++ /dev/null
-/* gdkglobals-quartz.c
- *
- * Copyright (C) 2005 Imendio AB
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-#include "gdktypes.h"
-#include "gdkquartz.h"
-#include "gdkscreen-quartz.h"
-
-GdkDisplay *_gdk_display = NULL;
-GdkQuartzScreen *_gdk_screen = NULL;
-GdkSurface *_gdk_root = NULL;
-GdkDeviceManager *_gdk_device_manager = NULL;
-
-GdkOSXVersion
-gdk_quartz_osx_version (void)
-{
- static gint32 minor = GDK_OSX_UNSUPPORTED;
-
- if (minor == GDK_OSX_UNSUPPORTED)
- {
- OSErr err = Gestalt (gestaltSystemVersionMinor, (SInt32*)&minor);
-
- g_return_val_if_fail (err == noErr, GDK_OSX_UNSUPPORTED);
- }
-
- if (minor < GDK_OSX_MIN)
- return GDK_OSX_UNSUPPORTED;
- else if (minor > GDK_OSX_CURRENT)
- return GDK_OSX_NEW;
- else
- return minor;
-}
+++ /dev/null
-/* gdkkeys-quartz.c
- *
- * Copyright (C) 2000 Red Hat, Inc.
- * Copyright (C) 2005 Imendio AB
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-/* Some parts of this code come from quartzKeyboard.c,
- * from the Apple X11 Server.
- *
- * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT
- * HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Except as contained in this notice, the name(s) of the above
- * copyright holders shall not be used in advertising or otherwise to
- * promote the sale, use or other dealings in this Software without
- * prior written authorization.
- */
-
-#include "config.h"
-
-#include <Carbon/Carbon.h>
-#include <AppKit/NSEvent.h>
-#include "gdk.h"
-#include "gdkquartzkeys.h"
-#include "gdkkeysprivate.h"
-#include "gdkkeysyms.h"
-
-#define NUM_KEYCODES 128
-#define KEYVALS_PER_KEYCODE 4
-
-static GdkKeymap *default_keymap = NULL;
-
-struct _GdkQuartzKeymap
-{
- GdkKeymap keymap;
-};
-
-struct _GdkQuartzKeymapClass
-{
- GdkKeymapClass keymap_class;
-};
-
-G_DEFINE_TYPE (GdkQuartzKeymap, gdk_quartz_keymap, GDK_TYPE_KEYMAP)
-
-GdkKeymap *
-_gdk_quartz_display_get_keymap (GdkDisplay *display)
-{
- if (default_keymap == NULL)
- default_keymap = g_object_new (gdk_quartz_keymap_get_type (), NULL);
-
- return default_keymap;
-}
-
-/* This is a table of all keyvals. Each keycode gets KEYVALS_PER_KEYCODE entries.
- * TThere is 1 keyval per modifier (Nothing, Shift, Alt, Shift+Alt);
- */
-static guint *keyval_array = NULL;
-
-static inline UniChar
-macroman2ucs (unsigned char c)
-{
- /* Precalculated table mapping MacRoman-128 to Unicode. Generated
- by creating single element CFStringRefs then extracting the
- first character. */
-
- static const unsigned short table[128] = {
- 0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc, 0xe1,
- 0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9, 0xe8,
- 0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1, 0xf3,
- 0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb, 0xfc,
- 0x2020, 0xb0, 0xa2, 0xa3, 0xa7, 0x2022, 0xb6, 0xdf,
- 0xae, 0xa9, 0x2122, 0xb4, 0xa8, 0x2260, 0xc6, 0xd8,
- 0x221e, 0xb1, 0x2264, 0x2265, 0xa5, 0xb5, 0x2202, 0x2211,
- 0x220f, 0x3c0, 0x222b, 0xaa, 0xba, 0x3a9, 0xe6, 0xf8,
- 0xbf, 0xa1, 0xac, 0x221a, 0x192, 0x2248, 0x2206, 0xab,
- 0xbb, 0x2026, 0xa0, 0xc0, 0xc3, 0xd5, 0x152, 0x153,
- 0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0xf7, 0x25ca,
- 0xff, 0x178, 0x2044, 0x20ac, 0x2039, 0x203a, 0xfb01, 0xfb02,
- 0x2021, 0xb7, 0x201a, 0x201e, 0x2030, 0xc2, 0xca, 0xc1,
- 0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3, 0xd4,
- 0xf8ff, 0xd2, 0xda, 0xdb, 0xd9, 0x131, 0x2c6, 0x2dc,
- 0xaf, 0x2d8, 0x2d9, 0x2da, 0xb8, 0x2dd, 0x2db, 0x2c7
- };
-
- if (c < 128)
- return c;
- else
- return table[c - 128];
-}
-
-const static struct {
- guint keycode;
- guint keyval;
- unsigned int modmask; /* So we can tell when a mod key is pressed/released */
-} modifier_keys[] = {
- { 54, GDK_KEY_Meta_R, NSCommandKeyMask },
- { 55, GDK_KEY_Meta_L, NSCommandKeyMask },
- { 56, GDK_KEY_Shift_L, NSShiftKeyMask },
- { 57, GDK_KEY_Caps_Lock, NSAlphaShiftKeyMask },
- { 58, GDK_KEY_Alt_L, NSAlternateKeyMask },
- { 59, GDK_KEY_Control_L, NSControlKeyMask },
- { 60, GDK_KEY_Shift_R, NSShiftKeyMask },
- { 61, GDK_KEY_Alt_R, NSAlternateKeyMask },
- { 62, GDK_KEY_Control_R, NSControlKeyMask }
-};
-
-const static struct {
- guint keycode;
- guint keyval;
-} function_keys[] = {
- { 122, GDK_KEY_F1 },
- { 120, GDK_KEY_F2 },
- { 99, GDK_KEY_F3 },
- { 118, GDK_KEY_F4 },
- { 96, GDK_KEY_F5 },
- { 97, GDK_KEY_F6 },
- { 98, GDK_KEY_F7 },
- { 100, GDK_KEY_F8 },
- { 101, GDK_KEY_F9 },
- { 109, GDK_KEY_F10 },
- { 103, GDK_KEY_F11 },
- { 111, GDK_KEY_F12 },
- { 105, GDK_KEY_F13 },
- { 107, GDK_KEY_F14 },
- { 113, GDK_KEY_F15 },
- { 106, GDK_KEY_F16 }
-};
-
-const static struct {
- guint keycode;
- guint normal_keyval, keypad_keyval;
-} known_numeric_keys[] = {
- { 65, GDK_KEY_period, GDK_KEY_KP_Decimal },
- { 67, GDK_KEY_asterisk, GDK_KEY_KP_Multiply },
- { 69, GDK_KEY_plus, GDK_KEY_KP_Add },
- { 75, GDK_KEY_slash, GDK_KEY_KP_Divide },
- { 76, GDK_KEY_Return, GDK_KEY_KP_Enter },
- { 78, GDK_KEY_minus, GDK_KEY_KP_Subtract },
- { 81, GDK_KEY_equal, GDK_KEY_KP_Equal },
- { 82, GDK_KEY_0, GDK_KEY_KP_0 },
- { 83, GDK_KEY_1, GDK_KEY_KP_1 },
- { 84, GDK_KEY_2, GDK_KEY_KP_2 },
- { 85, GDK_KEY_3, GDK_KEY_KP_3 },
- { 86, GDK_KEY_4, GDK_KEY_KP_4 },
- { 87, GDK_KEY_5, GDK_KEY_KP_5 },
- { 88, GDK_KEY_6, GDK_KEY_KP_6 },
- { 89, GDK_KEY_7, GDK_KEY_KP_7 },
- { 91, GDK_KEY_8, GDK_KEY_KP_8 },
- { 92, GDK_KEY_9, GDK_KEY_KP_9 }
-};
-
-/* These values aren't covered by gdk_unicode_to_keyval */
-const static struct {
- gunichar ucs_value;
- guint keyval;
-} special_ucs_table [] = {
- { 0x0001, GDK_KEY_Home },
- { 0x0003, GDK_KEY_Return },
- { 0x0004, GDK_KEY_End },
- { 0x0008, GDK_KEY_BackSpace },
- { 0x0009, GDK_KEY_Tab },
- { 0x000b, GDK_KEY_Page_Up },
- { 0x000c, GDK_KEY_Page_Down },
- { 0x000d, GDK_KEY_Return },
- { 0x001b, GDK_KEY_Escape },
- { 0x001c, GDK_KEY_Left },
- { 0x001d, GDK_KEY_Right },
- { 0x001e, GDK_KEY_Up },
- { 0x001f, GDK_KEY_Down },
- { 0x007f, GDK_KEY_Delete },
- { 0xf027, GDK_KEY_dead_acute },
- { 0xf060, GDK_KEY_dead_grave },
- { 0xf300, GDK_KEY_dead_grave },
- { 0xf0b4, GDK_KEY_dead_acute },
- { 0xf301, GDK_KEY_dead_acute },
- { 0xf385, GDK_KEY_dead_acute },
- { 0xf05e, GDK_KEY_dead_circumflex },
- { 0xf2c6, GDK_KEY_dead_circumflex },
- { 0xf302, GDK_KEY_dead_circumflex },
- { 0xf07e, GDK_KEY_dead_tilde },
- { 0xf2dc, GDK_KEY_dead_tilde },
- { 0xf303, GDK_KEY_dead_tilde },
- { 0xf342, GDK_KEY_dead_perispomeni },
- { 0xf0af, GDK_KEY_dead_macron },
- { 0xf304, GDK_KEY_dead_macron },
- { 0xf2d8, GDK_KEY_dead_breve },
- { 0xf306, GDK_KEY_dead_breve },
- { 0xf2d9, GDK_KEY_dead_abovedot },
- { 0xf307, GDK_KEY_dead_abovedot },
- { 0xf0a8, GDK_KEY_dead_diaeresis },
- { 0xf308, GDK_KEY_dead_diaeresis },
- { 0xf2da, GDK_KEY_dead_abovering },
- { 0xf30A, GDK_KEY_dead_abovering },
- { 0xf022, GDK_KEY_dead_doubleacute },
- { 0xf2dd, GDK_KEY_dead_doubleacute },
- { 0xf30B, GDK_KEY_dead_doubleacute },
- { 0xf2c7, GDK_KEY_dead_caron },
- { 0xf30C, GDK_KEY_dead_caron },
- { 0xf0be, GDK_KEY_dead_cedilla },
- { 0xf327, GDK_KEY_dead_cedilla },
- { 0xf2db, GDK_KEY_dead_ogonek },
- { 0xf328, GDK_KEY_dead_ogonek },
- { 0xfe5d, GDK_KEY_dead_iota },
- { 0xf323, GDK_KEY_dead_belowdot },
- { 0xf309, GDK_KEY_dead_hook },
- { 0xf31B, GDK_KEY_dead_horn },
- { 0xf02d, GDK_KEY_dead_stroke },
- { 0xf335, GDK_KEY_dead_stroke },
- { 0xf336, GDK_KEY_dead_stroke },
- { 0xf313, GDK_KEY_dead_abovecomma },
- /* { 0xf313, GDK_KEY_dead_psili }, */
- { 0xf314, GDK_KEY_dead_abovereversedcomma },
- /* { 0xf314, GDK_KEY_dead_dasia }, */
- { 0xf30F, GDK_KEY_dead_doublegrave },
- { 0xf325, GDK_KEY_dead_belowring },
- { 0xf2cd, GDK_KEY_dead_belowmacron },
- { 0xf331, GDK_KEY_dead_belowmacron },
- { 0xf32D, GDK_KEY_dead_belowcircumflex },
- { 0xf330, GDK_KEY_dead_belowtilde },
- { 0xf32E, GDK_KEY_dead_belowbreve },
- { 0xf324, GDK_KEY_dead_belowdiaeresis },
- { 0xf311, GDK_KEY_dead_invertedbreve },
- { 0xf02c, GDK_KEY_dead_belowcomma },
- { 0xf326, GDK_KEY_dead_belowcomma }
-};
-
-static void
-update_keymap (void)
-{
- const void *chr_data = NULL;
- guint *p;
- int i;
-
- /* Note: we could check only if building against the 10.5 SDK instead, but
- * that would make non-xml layouts not work in 32-bit which would be a quite
- * bad regression. This way, old unsupported layouts will just not work in
- * 64-bit.
- */
-#ifdef __LP64__
- TISInputSourceRef new_layout = TISCopyCurrentKeyboardLayoutInputSource ();
- CFDataRef layout_data_ref;
-
-#else
- KeyboardLayoutRef new_layout;
- KeyboardLayoutKind layout_kind;
-
- KLGetCurrentKeyboardLayout (&new_layout);
-#endif
-
- g_free (keyval_array);
- keyval_array = g_new0 (guint, NUM_KEYCODES * KEYVALS_PER_KEYCODE);
-
-#ifdef __LP64__
- layout_data_ref = (CFDataRef) TISGetInputSourceProperty
- (new_layout, kTISPropertyUnicodeKeyLayoutData);
-
- if (layout_data_ref)
- chr_data = CFDataGetBytePtr (layout_data_ref);
-
- if (chr_data == NULL)
- {
- g_error ("cannot get keyboard layout data");
- return;
- }
-#else
-
- /* Get the layout kind */
- KLGetKeyboardLayoutProperty (new_layout, kKLKind, (const void **)&layout_kind);
-
- /* 8-bit-only keyabord layout */
- if (layout_kind == kKLKCHRKind)
- {
- /* Get chr data */
- KLGetKeyboardLayoutProperty (new_layout, kKLKCHRData, (const void **)&chr_data);
-
- for (i = 0; i < NUM_KEYCODES; i++)
- {
- int j;
- UInt32 modifiers[] = {0, shiftKey, optionKey, shiftKey | optionKey};
-
- p = keyval_array + i * KEYVALS_PER_KEYCODE;
-
- for (j = 0; j < KEYVALS_PER_KEYCODE; j++)
- {
- UInt32 c, state = 0;
- UInt16 key_code;
- UniChar uc;
-
- key_code = modifiers[j] | i;
- c = KeyTranslate (chr_data, key_code, &state);
-
- if (state != 0)
- {
- UInt32 state2 = 0;
- c = KeyTranslate (chr_data, key_code | 128, &state2);
- }
-
- if (c != 0 && c != 0x10)
- {
- int k;
- gboolean found = FALSE;
-
- /* FIXME: some keyboard layouts (e.g. Russian) use a
- * different 8-bit character set. We should check
- * for this. Not a serious problem, because most
- * (all?) of these layouts also have a uchr version.
- */
- uc = macroman2ucs (c);
-
- for (k = 0; k < G_N_ELEMENTS (special_ucs_table); k++)
- {
- if (special_ucs_table[k].ucs_value == uc)
- {
- p[j] = special_ucs_table[k].keyval;
- found = TRUE;
- break;
- }
- }
-
- /* Special-case shift-tab since GTK+ expects
- * GDK_KEY_ISO_Left_Tab for that.
- */
- if (found && p[j] == GDK_KEY_Tab && modifiers[j] == shiftKey)
- p[j] = GDK_KEY_ISO_Left_Tab;
-
- if (!found)
- p[j] = gdk_unicode_to_keyval (uc);
- }
- }
-
- if (p[3] == p[2])
- p[3] = 0;
- if (p[2] == p[1])
- p[2] = 0;
- if (p[1] == p[0])
- p[1] = 0;
- if (p[0] == p[2] &&
- p[1] == p[3])
- p[2] = p[3] = 0;
- }
- }
- /* unicode keyboard layout */
- else if (layout_kind == kKLKCHRuchrKind || layout_kind == kKLuchrKind)
- {
- /* Get chr data */
- KLGetKeyboardLayoutProperty (new_layout, kKLuchrData, (const void **)&chr_data);
-#endif
-
- for (i = 0; i < NUM_KEYCODES; i++)
- {
- int j;
- UInt32 modifiers[] = {0, shiftKey, optionKey, shiftKey | optionKey};
- UniChar chars[4];
- UniCharCount nChars;
-
- p = keyval_array + i * KEYVALS_PER_KEYCODE;
-
- for (j = 0; j < KEYVALS_PER_KEYCODE; j++)
- {
- UInt32 state = 0;
- OSStatus err;
- UInt16 key_code;
- UniChar uc;
-
- key_code = modifiers[j] | i;
- err = UCKeyTranslate (chr_data, i, kUCKeyActionDisplay,
- (modifiers[j] >> 8) & 0xFF,
- LMGetKbdType(),
- 0,
- &state, 4, &nChars, chars);
-
- /* FIXME: Theoretically, we can get multiple UTF-16
- * values; we should convert them to proper unicode and
- * figure out whether there are really keyboard layouts
- * that give us more than one character for one
- * keypress.
- */
- if (err == noErr && nChars == 1)
- {
- int k;
- gboolean found = FALSE;
-
- /* A few <Shift><Option>keys return two characters,
- * the first of which is U+00a0, which isn't
- * interesting; so we return the second. More
- * sophisticated handling is the job of a
- * GtkIMContext.
- *
- * If state isn't zero, it means that it's a dead
- * key of some sort. Some of those are enumerated in
- * the special_ucs_table with the high nibble set to
- * f to push it into the private use range. Here we
- * do the same.
- */
- if (state != 0)
- chars[nChars - 1] |= 0xf000;
- uc = chars[nChars - 1];
-
- for (k = 0; k < G_N_ELEMENTS (special_ucs_table); k++)
- {
- if (special_ucs_table[k].ucs_value == uc)
- {
- p[j] = special_ucs_table[k].keyval;
- found = TRUE;
- break;
- }
- }
-
- /* Special-case shift-tab since GTK+ expects
- * GDK_KEY_ISO_Left_Tab for that.
- */
- if (found && p[j] == GDK_KEY_Tab && modifiers[j] == shiftKey)
- p[j] = GDK_KEY_ISO_Left_Tab;
-
- if (!found)
- p[j] = gdk_unicode_to_keyval (uc);
- }
- }
-
- if (p[3] == p[2])
- p[3] = 0;
- if (p[2] == p[1])
- p[2] = 0;
- if (p[1] == p[0])
- p[1] = 0;
- if (p[0] == p[2] &&
- p[1] == p[3])
- p[2] = p[3] = 0;
- }
-#ifndef __LP64__
- }
- else
- {
- g_error ("unknown type of keyboard layout (neither KCHR nor uchr)"
- " - not supported right now");
- }
-#endif
-
- for (i = 0; i < G_N_ELEMENTS (modifier_keys); i++)
- {
- p = keyval_array + modifier_keys[i].keycode * KEYVALS_PER_KEYCODE;
-
- if (p[0] == 0 && p[1] == 0 &&
- p[2] == 0 && p[3] == 0)
- p[0] = modifier_keys[i].keyval;
- }
-
- for (i = 0; i < G_N_ELEMENTS (function_keys); i++)
- {
- p = keyval_array + function_keys[i].keycode * KEYVALS_PER_KEYCODE;
-
- p[0] = function_keys[i].keyval;
- p[1] = p[2] = p[3] = 0;
- }
-
- for (i = 0; i < G_N_ELEMENTS (known_numeric_keys); i++)
- {
- p = keyval_array + known_numeric_keys[i].keycode * KEYVALS_PER_KEYCODE;
-
- if (p[0] == known_numeric_keys[i].normal_keyval)
- p[0] = known_numeric_keys[i].keypad_keyval;
- }
-
- if (default_keymap != NULL)
- g_signal_emit_by_name (default_keymap, "keys-changed");
-}
-
-static PangoDirection
-gdk_quartz_keymap_get_direction (GdkKeymap *keymap)
-{
- return PANGO_DIRECTION_NEUTRAL;
-}
-
-static gboolean
-gdk_quartz_keymap_have_bidi_layouts (GdkKeymap *keymap)
-{
- /* FIXME: Can we implement this? */
- return FALSE;
-}
-
-static gboolean
-gdk_quartz_keymap_get_caps_lock_state (GdkKeymap *keymap)
-{
- /* FIXME: Implement this. */
- return FALSE;
-}
-
-static gboolean
-gdk_quartz_keymap_get_num_lock_state (GdkKeymap *keymap)
-{
- /* FIXME: Implement this. */
- return FALSE;
-}
-
-static gboolean
-gdk_quartz_keymap_get_scroll_lock_state (GdkKeymap *keymap)
-{
- /* FIXME: Implement this. */
- return FALSE;
-}
-
-static gboolean
-gdk_quartz_keymap_get_entries_for_keyval (GdkKeymap *keymap,
- guint keyval,
- GdkKeymapKey **keys,
- gint *n_keys)
-{
- GArray *keys_array;
- int i;
-
- *n_keys = 0;
- keys_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
-
- for (i = 0; i < NUM_KEYCODES * KEYVALS_PER_KEYCODE; i++)
- {
- GdkKeymapKey key;
-
- if (keyval_array[i] != keyval)
- continue;
-
- (*n_keys)++;
-
- key.keycode = i / KEYVALS_PER_KEYCODE;
- key.group = (i % KEYVALS_PER_KEYCODE) >= 2;
- key.level = i % 2;
-
- g_array_append_val (keys_array, key);
- }
-
- *keys = (GdkKeymapKey *)g_array_free (keys_array, FALSE);
-
- return *n_keys > 0;;
-}
-
-static gboolean
-gdk_quartz_keymap_get_entries_for_keycode (GdkKeymap *keymap,
- guint hardware_keycode,
- GdkKeymapKey **keys,
- guint **keyvals,
- gint *n_entries)
-{
- GArray *keys_array, *keyvals_array;
- int i;
- guint *p;
-
- *n_entries = 0;
-
- if (hardware_keycode > NUM_KEYCODES)
- return FALSE;
-
- if (keys)
- keys_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
- else
- keys_array = NULL;
-
- if (keyvals)
- keyvals_array = g_array_new (FALSE, FALSE, sizeof (guint));
- else
- keyvals_array = NULL;
-
- p = keyval_array + hardware_keycode * KEYVALS_PER_KEYCODE;
-
- for (i = 0; i < KEYVALS_PER_KEYCODE; i++)
- {
- if (!p[i])
- continue;
-
- (*n_entries)++;
-
- if (keyvals_array)
- g_array_append_val (keyvals_array, p[i]);
-
- if (keys_array)
- {
- GdkKeymapKey key;
-
- key.keycode = hardware_keycode;
- key.group = i >= 2;
- key.level = i % 2;
-
- g_array_append_val (keys_array, key);
- }
- }
-
- if (keys)
- *keys = (GdkKeymapKey *)g_array_free (keys_array, FALSE);
-
- if (keyvals)
- *keyvals = (guint *)g_array_free (keyvals_array, FALSE);
-
- return *n_entries > 0;
-}
-
-#define GET_KEYVAL(keycode, group, level) (keyval_array[(keycode * KEYVALS_PER_KEYCODE + group * 2 + level)])
-
-static guint
-gdk_quartz_keymap_lookup_key (GdkKeymap *keymap,
- const GdkKeymapKey *key)
-{
- return GET_KEYVAL (key->keycode, key->group, key->level);
-}
-
-static guint
-translate_keysym (guint hardware_keycode,
- gint group,
- GdkModifierType state,
- gint *effective_group,
- gint *effective_level)
-{
- gint level;
- guint tmp_keyval;
-
- level = (state & GDK_SHIFT_MASK) ? 1 : 0;
-
- if (!(GET_KEYVAL (hardware_keycode, group, 0) || GET_KEYVAL (hardware_keycode, group, 1)) &&
- (GET_KEYVAL (hardware_keycode, 0, 0) || GET_KEYVAL (hardware_keycode, 0, 1)))
- group = 0;
-
- if (!GET_KEYVAL (hardware_keycode, group, level) &&
- GET_KEYVAL (hardware_keycode, group, 0))
- level = 0;
-
- tmp_keyval = GET_KEYVAL (hardware_keycode, group, level);
-
- if (state & GDK_LOCK_MASK)
- {
- guint upper = gdk_keyval_to_upper (tmp_keyval);
- if (upper != tmp_keyval)
- tmp_keyval = upper;
- }
-
- if (effective_group)
- *effective_group = group;
- if (effective_level)
- *effective_level = level;
-
- return tmp_keyval;
-}
-
-static gboolean
-gdk_quartz_keymap_translate_keyboard_state (GdkKeymap *keymap,
- guint hardware_keycode,
- GdkModifierType state,
- gint group,
- guint *keyval,
- gint *effective_group,
- gint *level,
- GdkModifierType *consumed_modifiers)
-{
- guint tmp_keyval;
- GdkModifierType bit;
-
- if (keyval)
- *keyval = 0;
- if (effective_group)
- *effective_group = 0;
- if (level)
- *level = 0;
- if (consumed_modifiers)
- *consumed_modifiers = 0;
-
- if (hardware_keycode < 0 || hardware_keycode >= NUM_KEYCODES)
- return FALSE;
-
- tmp_keyval = translate_keysym (hardware_keycode, group, state, level, effective_group);
-
- /* Check if modifiers modify the keyval */
- if (consumed_modifiers)
- {
- guint tmp_modifiers = (state & GDK_MODIFIER_MASK);
-
- for (bit = 1; bit <= tmp_modifiers; bit <<= 1)
- {
- if ((bit & tmp_modifiers) &&
- translate_keysym (hardware_keycode, group, state & ~bit,
- NULL, NULL) == tmp_keyval)
- tmp_modifiers &= ~bit;
- }
-
- *consumed_modifiers = tmp_modifiers;
- }
-
- if (keyval)
- *keyval = tmp_keyval;
-
- return TRUE;
-}
-
-static void
-gdk_quartz_keymap_add_virtual_modifiers (GdkKeymap *keymap,
- GdkModifierType *state)
-{
- if (*state & GDK_MOD2_MASK)
- *state |= GDK_META_MASK;
-}
-
-static gboolean
-gdk_quartz_keymap_map_virtual_modifiers (GdkKeymap *keymap,
- GdkModifierType *state)
-{
- if (*state & GDK_META_MASK)
- *state |= GDK_MOD2_MASK;
-
- return TRUE;
-}
-
-/* What sort of key event is this? Returns one of
- * GDK_KEY_PRESS, GDK_KEY_RELEASE, GDK_NOTHING (should be ignored)
- */
-GdkEventType
-_gdk_quartz_keys_event_type (NSEvent *event)
-{
- unsigned short keycode;
- unsigned int flags;
- int i;
-
- switch ([event type])
- {
- case NSKeyDown:
- return GDK_KEY_PRESS;
- case NSKeyUp:
- return GDK_KEY_RELEASE;
- case NSFlagsChanged:
- break;
- default:
- g_assert_not_reached ();
- }
-
- /* For flags-changed events, we have to find the special key that caused the
- * event, and see if it's in the modifier mask. */
- keycode = [event keyCode];
- flags = [event modifierFlags];
-
- for (i = 0; i < G_N_ELEMENTS (modifier_keys); i++)
- {
- if (modifier_keys[i].keycode == keycode)
- {
- if (flags & modifier_keys[i].modmask)
- return GDK_KEY_PRESS;
- else
- return GDK_KEY_RELEASE;
- }
- }
-
- /* Some keypresses (eg: Expose' activations) seem to trigger flags-changed
- * events for no good reason. Ignore them! */
- return GDK_NOTHING;
-}
-
-gboolean
-_gdk_quartz_keys_is_modifier (guint keycode)
-{
- gint i;
-
- for (i = 0; i < G_N_ELEMENTS (modifier_keys); i++)
- {
- if (modifier_keys[i].modmask == 0)
- break;
-
- if (modifier_keys[i].keycode == keycode)
- return TRUE;
- }
-
- return FALSE;
-}
-
-static void
-input_sources_changed_notification (CFNotificationCenterRef center,
- void *observer,
- CFStringRef name,
- const void *object,
- CFDictionaryRef userInfo)
-{
- update_keymap ();
-}
-
-static void
-gdk_quartz_keymap_init (GdkQuartzKeymap *keymap)
-{
- update_keymap ();
- CFNotificationCenterAddObserver (CFNotificationCenterGetDistributedCenter (),
- keymap,
- input_sources_changed_notification,
- CFSTR ("AppleSelectedInputSourcesChangedNotification"),
- NULL,
- CFNotificationSuspensionBehaviorDeliverImmediately);
-}
-
-static void
-gdk_quartz_keymap_finalize (GObject *object)
-{
- CFNotificationCenterRemoveObserver (CFNotificationCenterGetDistributedCenter (),
- object,
- CFSTR ("AppleSelectedInputSourcesChangedNotification"),
- NULL);
-
- G_OBJECT_CLASS (gdk_quartz_keymap_parent_class)->finalize (object);
-}
-
-static void
-gdk_quartz_keymap_class_init (GdkQuartzKeymapClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GdkKeymapClass *keymap_class = GDK_KEYMAP_CLASS (klass);
-
- object_class->finalize = gdk_quartz_keymap_finalize;
-
- keymap_class->get_direction = gdk_quartz_keymap_get_direction;
- keymap_class->have_bidi_layouts = gdk_quartz_keymap_have_bidi_layouts;
- keymap_class->get_caps_lock_state = gdk_quartz_keymap_get_caps_lock_state;
- keymap_class->get_num_lock_state = gdk_quartz_keymap_get_num_lock_state;
- keymap_class->get_scroll_lock_state = gdk_quartz_keymap_get_scroll_lock_state;
- keymap_class->get_entries_for_keyval = gdk_quartz_keymap_get_entries_for_keyval;
- keymap_class->get_entries_for_keycode = gdk_quartz_keymap_get_entries_for_keycode;
- keymap_class->lookup_key = gdk_quartz_keymap_lookup_key;
- keymap_class->translate_keyboard_state = gdk_quartz_keymap_translate_keyboard_state;
- keymap_class->add_virtual_modifiers = gdk_quartz_keymap_add_virtual_modifiers;
- keymap_class->map_virtual_modifiers = gdk_quartz_keymap_map_virtual_modifiers;
-}
+++ /dev/null
-/*
- * Copyright © 2017 Tom Schoonjans
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-
-#include <glib.h>
-#include <gio/gio.h>
-
-#include "gdkmonitor-quartz.h"
-#include "gdkscreen-quartz.h"
-
-
-G_DEFINE_TYPE (GdkQuartzMonitor, gdk_quartz_monitor, GDK_TYPE_MONITOR)
-
-static void
-gdk_quartz_monitor_get_workarea (GdkMonitor *monitor,
- GdkRectangle *dest)
-{
- GdkQuartzScreen *quartz_screen = GDK_QUARTZ_SCREEN(_gdk_screen);
- GdkQuartzMonitor *quartz_monitor = GDK_QUARTZ_MONITOR(monitor);
-
- GDK_QUARTZ_ALLOC_POOL;
-
- NSArray *array = [NSScreen screens];
- if (quartz_monitor->monitor_num < [array count])
- {
- NSScreen *screen = [array objectAtIndex:quartz_monitor->monitor_num];
- NSRect rect = [screen visibleFrame];
-
- dest->x = rect.origin.x - quartz_screen->min_x;
- dest->y = quartz_screen->height - (rect.origin.y + rect.size.height) + quartz_screen->min_y;
- dest->width = rect.size.width;
- dest->height = rect.size.height;
- }
- else
- *dest = monitor->geometry;
-
- GDK_QUARTZ_RELEASE_POOL;
-}
-
-static void
-gdk_quartz_monitor_init (GdkQuartzMonitor *monitor)
-{
-}
-
-static void
-gdk_quartz_monitor_class_init (GdkQuartzMonitorClass *class)
-{
- GDK_MONITOR_CLASS (class)->get_workarea = gdk_quartz_monitor_get_workarea;
-}
-
+++ /dev/null
-/*
- * Copyright © 2017 Tom Schoonjans
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __GDK_QUARTZ_MONITOR_PRIVATE_H__
-#define __GDK_QUARTZ_MONITOR_PRIVATE_H__
-
-#include <glib.h>
-#include <gio/gio.h>
-
-#include "gdkmonitorprivate.h"
-
-#include "gdkquartzmonitor.h"
-#include "gdkprivate-quartz.h"
-
-struct _GdkQuartzMonitor
-{
- GdkMonitor parent;
-
- gint monitor_num;
-};
-
-struct _GdkQuartzMonitorClass {
- GdkMonitorClass parent_class;
-};
-
-#endif
-
+++ /dev/null
-/* gdksurface-quartz.c
- *
- * Copyright (C) 2005-2007 Imendio AB
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __GDK_PRIVATE_QUARTZ_H__
-#define __GDK_PRIVATE_QUARTZ_H__
-
-#define GDK_QUARTZ_ALLOC_POOL NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]
-#define GDK_QUARTZ_RELEASE_POOL [pool release]
-
-#include <gdk/quartz/gdkquartz.h>
-#include <gdk/quartz/gdkdevicemanager-core-quartz.h>
-#include <gdk/quartz/gdkdnd-quartz.h>
-#include <gdk/quartz/gdkscreen-quartz.h>
-#include <gdk/quartz/gdksurface-quartz.h>
-
-#include <gdk/gdk.h>
-
-#include "gdkinternals.h"
-
-#include "config.h"
-
-extern GdkDisplay *_gdk_display;
-extern GdkQuartzScreen *_gdk_screen;
-extern GdkSurface *_gdk_root;
-extern GdkDeviceManager *_gdk_device_manager;
-
-extern GdkDragContext *_gdk_quartz_drag_source_context;
-
-#define GDK_SURFACE_IS_QUARTZ(win) (GDK_IS_SURFACE_IMPL_QUARTZ (((GdkSurface *)win)->impl))
-
-/* Initialization */
-void _gdk_quartz_surface_init_windowing (GdkDisplay *display);
-void _gdk_quartz_events_init (void);
-void _gdk_quartz_event_loop_init (void);
-
-/* Cursor */
-NSCursor *_gdk_quartz_cursor_get_ns_cursor (GdkCursor *cursor);
-
-/* Events */
-typedef enum {
- GDK_QUARTZ_EVENT_SUBTYPE_EVENTLOOP
-} GdkQuartzEventSubType;
-
-void _gdk_quartz_events_update_focus_window (GdkSurface *new_window,
- gboolean got_focus);
-void _gdk_quartz_events_send_map_event (GdkSurface *window);
-
-GdkModifierType _gdk_quartz_events_get_current_keyboard_modifiers (void);
-GdkModifierType _gdk_quartz_events_get_current_mouse_modifiers (void);
-
-void _gdk_quartz_events_break_all_grabs (guint32 time);
-
-/* Event loop */
-gboolean _gdk_quartz_event_loop_check_pending (void);
-NSEvent * _gdk_quartz_event_loop_get_pending (void);
-void _gdk_quartz_event_loop_release_event (NSEvent *event);
-
-/* Keys */
-GdkEventType _gdk_quartz_keys_event_type (NSEvent *event);
-gboolean _gdk_quartz_keys_is_modifier (guint keycode);
-void _gdk_quartz_synthesize_null_key_event (GdkSurface *window);
-
-/* Drag and Drop */
-GdkDragContext * _gdk_quartz_surface_drag_begin (GdkSurface *window,
- GdkDevice *device,
- GList *targets,
- gint x_root,
- gint y_root);
-
-/* Display */
-
-GdkDisplay * _gdk_quartz_display_open (const gchar *name);
-
-
-/* Screen */
-GdkQuartzScreen *_gdk_quartz_screen_new (void);
-void _gdk_quartz_screen_update_window_sizes (GdkQuartzScreen *screen);
-
-/* Screen methods - events */
-gboolean _gdk_quartz_get_setting (const gchar *name,
- GValue *value);
-
-
-/* Window */
-gboolean _gdk_quartz_surface_is_ancestor (GdkSurface *ancestor,
- GdkSurface *window);
-void _gdk_quartz_surface_gdk_xy_to_xy (gint gdk_x,
- gint gdk_y,
- gint *ns_x,
- gint *ns_y);
-void _gdk_quartz_surface_xy_to_gdk_xy (gint ns_x,
- gint ns_y,
- gint *gdk_x,
- gint *gdk_y);
-void _gdk_quartz_surface_nspoint_to_gdk_xy (NSPoint point,
- gint *x,
- gint *y);
-GdkSurface *_gdk_quartz_surface_find_child (GdkSurface *window,
- gint x,
- gint y,
- gboolean get_toplevel);
-void _gdk_quartz_surface_attach_to_parent (GdkSurface *window);
-void _gdk_quartz_surface_detach_from_parent (GdkSurface *window);
-void _gdk_quartz_surface_did_become_main (GdkSurface *window);
-void _gdk_quartz_surface_did_resign_main (GdkSurface *window);
-void _gdk_quartz_surface_debug_highlight (GdkSurface *window,
- gint number);
-
-void _gdk_quartz_surface_update_position (GdkSurface *window);
-void _gdk_quartz_surface_update_fullscreen_state (GdkSurface *window);
-
-/* Window methods - property */
-gboolean _gdk_quartz_surface_get_property (GdkSurface *window,
- GdkAtom property,
- GdkAtom type,
- gulong offset,
- gulong length,
- gint pdelete,
- GdkAtom *actual_property_type,
- gint *actual_format_type,
- gint *actual_length,
- guchar **data);
-void _gdk_quartz_surface_change_property (GdkSurface *window,
- GdkAtom property,
- GdkAtom type,
- gint format,
- GdkPropMode mode,
- const guchar *data,
- gint nelements);
-void _gdk_quartz_surface_delete_property (GdkSurface *window,
- GdkAtom property);
-
-
-#endif /* __GDK_PRIVATE_QUARTZ_H__ */
+++ /dev/null
-
-/* gdkquartz.h
- *
- * Copyright (C) 2005-2007 Imendio AB
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __GDK_QUARTZ_H__
-#define __GDK_QUARTZ_H__
-
-#include <AppKit/AppKit.h>
-
-#include <gdk/gdk.h>
-
-G_BEGIN_DECLS
-
-/* NSInteger only exists in Leopard and newer. This check has to be
- * done after inclusion of the system headers. If NSInteger has not
- * been defined, we know for sure that we are on 32-bit.
- */
-#ifndef NSINTEGER_DEFINED
-typedef int NSInteger;
-typedef unsigned int NSUInteger;
-#endif
-
-#ifndef CGFLOAT_DEFINED
-typedef float CGFloat;
-#endif
-
-typedef enum
-{
- GDK_OSX_UNSUPPORTED = 0,
- GDK_OSX_MIN = 4,
- GDK_OSX_TIGER = 4,
- GDK_OSX_LEOPARD = 5,
- GDK_OSX_SNOW_LEOPARD = 6,
- GDK_OSX_LION = 7,
- GDK_OSX_MOUNTAIN_LION = 8,
- GDK_OSX_MAVERICKS = 9,
- GDK_OSX_YOSEMITE = 10,
- GDK_OSX_EL_CAPITAN = 11,
- GDK_OSX_SIERRA = 12,
- GDK_OSX_HIGH_SIERRA = 13,
- GDK_OSX_MOJAVE = 14,
- GDK_OSX_CURRENT = 14,
- GDK_OSX_NEW = 99
-} GdkOSXVersion;
-
-GDK_AVAILABLE_IN_ALL
-GdkOSXVersion gdk_quartz_osx_version (void);
-
-GDK_AVAILABLE_IN_ALL
-GdkAtom gdk_quartz_pasteboard_type_to_atom_libgtk_only (NSString *type);
-GDK_AVAILABLE_IN_ALL
-NSString *gdk_quartz_target_to_pasteboard_type_libgtk_only (const gchar *target);
-GDK_AVAILABLE_IN_ALL
-NSString *gdk_quartz_atom_to_pasteboard_type_libgtk_only (GdkAtom atom);
-
-G_END_DECLS
-
-#define __GDKQUARTZ_H_INSIDE__
-
-#include <gdk/quartz/gdkquartzcursor.h>
-#include <gdk/quartz/gdkquartzdevice-core.h>
-#include <gdk/quartz/gdkquartzdevicemanager-core.h>
-#include <gdk/quartz/gdkquartzdisplay.h>
-#include <gdk/quartz/gdkquartzdisplaymanager.h>
-#include <gdk/quartz/gdkquartzdnd.h>
-#include <gdk/quartz/gdkquartzkeys.h>
-#include <gdk/quartz/gdkquartzmonitor.h>
-#include <gdk/quartz/gdkquartzscreen.h>
-#include <gdk/quartz/gdkquartzutils.h>
-#include <gdk/quartz/gdkquartzsurface.h>
-
-#undef __GDKQUARTZ_H_INSIDE__
-
-#endif /* __GDK_QUARTZ_H__ */
+++ /dev/null
-/* gdkquartzcursor.h
- *
- * Copyright (C) 2005-2007 Imendio AB
- * Copyright (C) 2010 Kristian Rietveld <kris@gtk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __GDK_QUARTZ_CURSOR_H__
-#define __GDK_QUARTZ_CURSOR_H__
-
-#if !defined(__GDKQUARTZ_H_INSIDE__) && !defined (GTK_COMPILATION)
-#error "Only <gdk/quartz/gdkquartz.h> can be included directly."
-#endif
-
-#include <gdk/gdk.h>
-
-G_BEGIN_DECLS
-
-#define GDK_TYPE_QUARTZ_CURSOR (gdk_quartz_cursor_get_type ())
-#define GDK_QUARTZ_CURSOR(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_QUARTZ_CURSOR, GdkQuartzCursor))
-#define GDK_QUARTZ_CURSOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_QUARTZ_CURSOR, GdkQuartzCursorClass))
-#define GDK_IS_QUARTZ_CURSOR(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_QUARTZ_CURSOR))
-#define GDK_IS_QUARTZ_CURSOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_QUARTZ_CURSOR))
-#define GDK_QUARTZ_CURSOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_QUARTZ_CURSOR, GdkQuartzCursorClass))
-
-#ifdef GTK_COMPILATION
-typedef struct _GdkQuartzCursor GdkQuartzCursor;
-#else
-typedef GdkCursor GdkQuartzCursor;
-#endif
-typedef struct _GdkQuartzCursorClass GdkQuartzCursorClass;
-
-GDK_AVAILABLE_IN_ALL
-GType gdk_quartz_cursor_get_type (void);
-
-G_END_DECLS
-
-#endif /* __GDK_QUARTZ_CURSOR_H__ */
+++ /dev/null
-/* GDK - The GIMP Drawing Kit
- * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __GDK_QUARTZ_DEVICE_CORE_H__
-#define __GDK_QUARTZ_DEVICE_CORE_H__
-
-#if !defined(__GDKQUARTZ_H_INSIDE__) && !defined (GTK_COMPILATION)
-#error "Only <gdk/quartz/gdkquartz.h> can be included directly."
-#endif
-
-#include <gdk/gdk.h>
-
-G_BEGIN_DECLS
-
-#define GDK_TYPE_QUARTZ_DEVICE_CORE (gdk_quartz_device_core_get_type ())
-#define GDK_QUARTZ_DEVICE_CORE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_QUARTZ_DEVICE_CORE, GdkQuartzDeviceCore))
-#define GDK_QUARTZ_DEVICE_CORE_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), GDK_TYPE_QUARTZ_DEVICE_CORE, GdkQuartzDeviceCoreClass))
-#define GDK_IS_QUARTZ_DEVICE_CORE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_QUARTZ_DEVICE_CORE))
-#define GDK_IS_QUARTZ_DEVICE_CORE_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), GDK_TYPE_QUARTZ_DEVICE_CORE))
-#define GDK_QUARTZ_DEVICE_CORE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDK_TYPE_QUARTZ_DEVICE_CORE, GdkQuartzDeviceCoreClass))
-
-typedef struct _GdkQuartzDeviceCore GdkQuartzDeviceCore;
-typedef struct _GdkQuartzDeviceCoreClass GdkQuartzDeviceCoreClass;
-
-GDK_AVAILABLE_IN_ALL
-GType gdk_quartz_device_core_get_type (void) G_GNUC_CONST;
-
-G_END_DECLS
-
-#endif /* __GDK_QUARTZ_DEVICE_CORE_H__ */
+++ /dev/null
-/* GDK - The GIMP Drawing Kit
- * Copyright (C) 2009 Carlos Garnacho <carlosg@gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __GDK_QUARTZ_DEVICE_MANAGER_CORE_H__
-#define __GDK_QUARTZ_DEVICE_MANAGER_CORE_H__
-
-#if !defined(__GDKQUARTZ_H_INSIDE__) && !defined (GTK_COMPILATION)
-#error "Only <gdk/quartz/gdkquartz.h> can be included directly."
-#endif
-
-#include <gdk/gdk.h>
-
-G_BEGIN_DECLS
-
-#define GDK_TYPE_QUARTZ_DEVICE_MANAGER_CORE (gdk_quartz_device_manager_core_get_type ())
-#define GDK_QUARTZ_DEVICE_MANAGER_CORE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_QUARTZ_DEVICE_MANAGER_CORE, GdkQuartzDeviceManagerCore))
-#define GDK_QUARTZ_DEVICE_MANAGER_CORE_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), GDK_TYPE_QUARTZ_DEVICE_MANAGER_CORE, GdkQuartzDeviceManagerCoreClass))
-#define GDK_IS_QUARTZ_DEVICE_MANAGER_CORE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_QUARTZ_DEVICE_MANAGER_CORE))
-#define GDK_IS_QUARTZ_DEVICE_MANAGER_CORE_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), GDK_TYPE_QUARTZ_DEVICE_MANAGER_CORE))
-#define GDK_QUARTZ_DEVICE_MANAGER_CORE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDK_TYPE_QUARTZ_DEVICE_MANAGER_CORE, GdkQuartzDeviceManagerCoreClass))
-
-typedef struct _GdkQuartzDeviceManagerCore GdkQuartzDeviceManagerCore;
-typedef struct _GdkQuartzDeviceManagerCoreClass GdkQuartzDeviceManagerCoreClass;
-
-
-GDK_AVAILABLE_IN_ALL
-GType gdk_quartz_device_manager_core_get_type (void) G_GNUC_CONST;
-
-
-G_END_DECLS
-
-#endif /* __GDK_QUARTZ_DEVICE_MANAGER_CORE_H__ */
+++ /dev/null
-/* gdkquartzdisplay.h
- *
- * Copyright (C) 2005-2007 Imendio AB
- * Copyright (C) 2010 Kristian Rietveld <kris@gtk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __GDK_QUARTZ_DISPLAY_H__
-#define __GDK_QUARTZ_DISPLAY_H__
-
-#if !defined(__GDKQUARTZ_H_INSIDE__) && !defined (GTK_COMPILATION)
-#error "Only <gdk/quartz/gdkquartz.h> can be included directly."
-#endif
-
-#include <gdk/gdk.h>
-
-G_BEGIN_DECLS
-
-#define GDK_TYPE_QUARTZ_DISPLAY (gdk_quartz_display_get_type ())
-#define GDK_QUARTZ_DISPLAY(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_QUARTZ_DISPLAY, GdkQuartzDisplay))
-#define GDK_QUARTZ_DISPLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_QUARTZ_DISPLAY, GdkQuartzDisplayClass))
-#define GDK_IS_QUARTZ_DISPLAY(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_QUARTZ_DISPLAY))
-#define GDK_IS_QUARTZ_DISPLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_QUARTZ_DISPLAY))
-#define GDK_QUARTZ_DISPLAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_QUARTZ_DISPLAY, GdkQuartzDisplayClass))
-
-#ifdef GTK_COMPILATION
-typedef struct _GdkQuartzDisplay GdkQuartzDisplay;
-#else
-typedef GdkDisplay GdkQuartzDisplay;
-#endif
-typedef struct _GdkQuartzDisplayClass GdkQuartzDisplayClass;
-
-
-GDK_AVAILABLE_IN_ALL
-GType gdk_quartz_display_get_type (void);
-
-G_END_DECLS
-
-#endif /* __GDK_QUARTZ_DISPLAY_H__ */
+++ /dev/null
-/* gdkquartzdisplaymanager.h
- *
- * Copyright (C) 2005-2007 Imendio AB
- * Copyright 2010 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __GDK_QUARTZ_DISPLAY_MANAGER_H__
-#define __GDK_QUARTZ_DISPLAY_MANAGER_H__
-
-#if !defined(__GDKQUARTZ_H_INSIDE__) && !defined (GTK_COMPILATION)
-#error "Only <gdk/quartz/gdkquartz.h> can be included directly."
-#endif
-
-#include <gdk/gdk.h>
-
-G_BEGIN_DECLS
-
-#define GDK_TYPE_QUARTZ_DISPLAY_MANAGER (gdk_quartz_display_manager_get_type ())
-#define GDK_QUARTZ_DISPLAY_MANAGER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_QUARTZ_DISPLAY_MANAGER, GdkQuartzDisplayManager))
-
-#ifdef GTK_COMPILATION
-typedef struct _GdkQuartzDisplayManager GdkQuartzDisplayManager;
-#else
-typedef GdkDisplayManager _GdkQuartzDisplayManager;
-#endif
-typedef struct _GdkDisplayManagerClass GdkQuartzDisplayManagerClass;
-
-
-GDK_AVAILABLE_IN_ALL
-GType gdk_quartz_display_manager_get_type (void);
-
-G_END_DECLS
-
-#endif /* __GDK_QUARTZ_DISPLAY_MANAGER_H__ */
+++ /dev/null
-/* gdkquartzdnd.h
- *
- * Copyright (C) 2010 Kristian Rietveld <kris@gtk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __GDK_QUARTZ_DND_H__
-#define __GDK_QUARTZ_DND_H__
-
-#if !defined(__GDKQUARTZ_H_INSIDE__) && !defined (GTK_COMPILATION)
-#error "Only <gdk/quartz/gdkquartz.h> can be included directly."
-#endif
-
-#include <gdk/gdk.h>
-
-G_BEGIN_DECLS
-
-#define GDK_TYPE_QUARTZ_DRAG_CONTEXT (gdk_quartz_drag_context_get_type ())
-#define GDK_QUARTZ_DRAG_CONTEXT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_QUARTZ_DRAG_CONTEXT, GdkQuartzDragContext))
-#define GDK_QUARTZ_DRAG_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_QUARTZ_DRAG_CONTEXT, GdkQuartzDragContextClass))
-#define GDK_IS_QUARTZ_DRAG_CONTEXT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_QUARTZ_DRAG_CONTEXT))
-#define GDK_IS_QUARTZ_DRAG_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_QUARTZ_DRAG_CONTEXT))
-#define GDK_QUARTZ_DRAG_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_QUARTZ_DRAG_CONTEXT, GdkQuartzDragContextClass))
-
-#ifdef GTK_COMPILATION
-typedef struct _GdkQuartzDragContext GdkQuartzDragContext;
-#else
-typedef GdkDragContext GdkQuartzDragContext;
-#endif
-typedef struct _GdkQuartzDragContextClass GdkQuartzDragContextClass;
-
-
-GDK_AVAILABLE_IN_ALL
-GType gdk_quartz_drag_context_get_type (void);
-
-GDK_AVAILABLE_IN_ALL
-id gdk_quartz_drag_context_get_dragging_info_libgtk_only (GdkDragContext *context);
-
-GDK_AVAILABLE_IN_ALL
-GdkDragContext *gdk_quartz_drag_source_context_libgtk_only (void);
-
-G_END_DECLS
-
-#endif /* __GDK_QUARTZ_DRAG_CONTEXT_H__ */
+++ /dev/null
-/* gdkquartzkeyd.h
- *
- * Copyright (C) 2005 Imendio AB
- * Copyright (C) 2010 Kristian Rietveld <kris@gtk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __GDK_QUARTZ_KEYS_H__
-#define __GDK_QUARTZ_KEYS_H__
-
-#if !defined (__GDKQUARTZ_H_INSIDE__) && !defined (GTK_COMPILATION)
-#error "Only <gdk/quartz/gdkquartz.h> can be included directly."
-#endif
-
-#include <gdk/gdk.h>
-
-G_BEGIN_DECLS
-
-#define GDK_TYPE_QUARTZ_KEYMAP (gdk_quartz_keymap_get_type ())
-#define GDK_QUARTZ_KEYMAP(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_QUARTZ_KEYMAP, GdkQuartzKeymap))
-#define GDK_QUARTZ_KEYMAP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_QUARTZ_KEYMAP, GdkQuartzKeymapClass))
-#define GDK_IS_QUARTZ_KEYMAP(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_QUARTZ_KEYMAP))
-#define GDK_IS_QUARTZ_KEYMAP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_QUARTZ_KEYMAP))
-#define GDK_QUARTZ_KEYMAP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_QUARTZ_KEYMAP, GdkQuartzKeymapClass))
-
-#ifdef GTK_COMPILATION
-typedef struct _GdkQuartzKeymap GdkQuartzKeymap;
-#else
-typedef GdkKeymap GdkQuartzKeymap;
-#endif
-typedef struct _GdkQuartzKeymapClass GdkQuartzKeymapClass;
-
-GDK_AVAILABLE_IN_ALL
-GType gdk_quartz_keymap_get_type (void);
-
-G_END_DECLS
-
-#endif /* __GDK_QUARTZ_KEYS_H__ */
+++ /dev/null
-/*
- * gdkquartzmonitor.h
- *
- * Copyright 2017 Tom Schoonjans
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __GDK_QUARTZ_MONITOR_H__
-#define __GDK_QUARTZ_MONITOR_H__
-
-#if !defined (__GDKQUARTZ_H_INSIDE__) && !defined (GTK_COMPILATION)
-#error "Only <gdk/quartz/gdkquartz.h> can be included directly."
-#endif
-
-#include <gdk/gdkmonitor.h>
-
-G_BEGIN_DECLS
-
-#define GDK_TYPE_QUARTZ_MONITOR (gdk_quartz_monitor_get_type ())
-#define GDK_QUARTZ_MONITOR(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_QUARTZ_MONITOR, GdkQuartzMonitor))
-#define GDK_IS_QUARTZ_MONITOR(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_QUARTZ_MONITOR))
-
-typedef struct _GdkQuartzMonitor GdkQuartzMonitor;
-typedef struct _GdkQuartzMonitorClass GdkQuartzMonitorClass;
-
-GDK_AVAILABLE_IN_ALL
-GType gdk_quartz_monitor_get_type (void) G_GNUC_CONST;
-
-
-G_END_DECLS
-
-#endif /* __GDK_QUARTZ_MONITOR_H__ */
-
+++ /dev/null
-/* gdkquartzscreen.h
- *
- * Copyright (C) 2009, 2010 Kristian Rietveld <kris@gtk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __GDK_QUARTZ_SCREEN_H__
-#define __GDK_QUARTZ_SCREEN_H__
-
-#if !defined(__GDKQUARTZ_H_INSIDE__) && !defined (GTK_COMPILATION)
-#error "Only <gdk/quartz/gdkquartz.h> can be included directly."
-#endif
-
-G_BEGIN_DECLS
-
-#include <gdk/gdk.h>
-
-#define GDK_TYPE_QUARTZ_SCREEN (gdk_quartz_screen_get_type ())
-#define GDK_QUARTZ_SCREEN(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_QUARTZ_SCREEN, GdkQuartzScreen))
-#define GDK_QUARTZ_SCREEN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_QUARTZ_SCREEN, GdkQuartzScreenClass))
-#define GDK_IS_QUARTZ_SCREEN(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_QUARTZ_SCREEN))
-#define GDK_IS_QUARTZ_SCREEN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_QUARTZ_SCREEN))
-#define GDK_QUARTZ_SCREEN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_QUARTZ_SCREEN, GdkQuartzScreenClass))
-
-typedef struct _GdkQuartzScreen GdkQuartzScreen;
-typedef struct _GdkQuartzScreenClass GdkQuartzScreenClass;
-
-
-GDK_AVAILABLE_IN_ALL
-GType gdk_quartz_screen_get_type (void);
-
-G_END_DECLS
-
-#endif /* _GDK_QUARTZ_SCREEN_H_ */
+++ /dev/null
-/* gdkquartzsurface.h
- *
- * Copyright (C) 2005 Imendio AB
- * Copyright (C) 2010 Kristian Rietveld <kris@gtk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __GDK_QUARTZ_SURFACE_H__
-#define __GDK_QUARTZ_SURFACE_H__
-
-#if !defined (__GDKQUARTZ_H_INSIDE__) && !defined (GTK_COMPILATION)
-#error "Only <gdk/quartz/gdkquartz.h> can be included directly."
-#endif
-
-#include <gdk/gdk.h>
-
-G_BEGIN_DECLS
-
-#define GDK_TYPE_QUARTZ_SURFACE (gdk_quartz_surface_get_type ())
-#define GDK_QUARTZ_SURFACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_QUARTZ_SURFACE, GdkQuartzSurface))
-#define GDK_QUARTZ_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_QUARTZ_SURFACE, GdkQuartzSurfaceClass))
-#define GDK_IS_QUARTZ_SURFACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_QUARTZ_SURFACE))
-#define GDK_IS_QUARTZ_SURFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_QUARTZ_SURFACE))
-#define GDK_QUARTZ_SURFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_QUARTZ_SURFACE, GdkQuartzSurfaceClass))
-
-#ifdef GTK_COMPILATION
-typedef struct _GdkQuartzSurface GdkQuartzSurface;
-#else
-typedef GdkSurface GdkQuartzSurface;
-#endif
-typedef struct _GdkQuartzSurfaceClass GdkQuartzSurfaceClass;
-
-GDK_AVAILABLE_IN_ALL
-GType gdk_quartz_surface_get_type (void);
-
-GDK_AVAILABLE_IN_ALL
-NSWindow *gdk_quartz_surface_get_nswindow (GdkSurface *window);
-GDK_AVAILABLE_IN_ALL
-NSView *gdk_quartz_surface_get_nsview (GdkSurface *window);
-
-G_END_DECLS
-
-#endif /* __GDK_QUARTZ_SURFACE_H__ */
+++ /dev/null
-/* gdkquartzutils.h
- *
- * Copyright (C) 2005 Imendio AB
- * Copyright (C) 2010 Kristian Rietveld <kris@gtk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __GDK_QUARTZ_UTILS_H__
-#define __GDK_QUARTZ_UTILS_H__
-
-#if !defined (__GDKQUARTZ_H_INSIDE__) && !defined (GTK_COMPILATION)
-#error "Only <gdk/quartz/gdkquartz.h> can be included directly."
-#endif
-
-#include <gdk/gdk.h>
-
-G_BEGIN_DECLS
-
-GDK_AVAILABLE_IN_ALL
-NSImage *gdk_quartz_pixbuf_to_ns_image_libgtk_only (GdkPixbuf *pixbuf);
-GDK_AVAILABLE_IN_ALL
-NSEvent *gdk_quartz_event_get_nsevent (GdkEvent *event);
-GDK_AVAILABLE_IN_ALL
-gunichar gdk_quartz_get_key_equivalent (guint key);
-
-G_END_DECLS
-
-#endif /* __GDK_QUARTZ_UTILS_H__ */
+++ /dev/null
-/* gdkscreen-quartz.c
- *
- * Copyright (C) 2005 Imendio AB
- * Copyright (C) 2009,2010 Kristian Rietveld <kris@gtk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-
-#include <gdk/gdk.h>
-
-#include "gdkprivate-quartz.h"
-#include "gdkdisplay-quartz.h"
-#include "gdkmonitor-quartz.h"
-
-
-/* A couple of notes about this file are in order. In GDK, a
- * GdkScreen can contain multiple monitors. A GdkScreen has an
- * associated root window, in which the monitors are placed. The
- * root window "spans" all monitors. The origin is at the top-left
- * corner of the root window.
- *
- * Cocoa works differently. The system has a "screen" (NSScreen) for
- * each monitor that is connected (note the conflicting definitions
- * of screen). The screen containing the menu bar is screen 0 and the
- * bottom-left corner of this screen is the origin of the "monitor
- * coordinate space". All other screens are positioned according to this
- * origin. If the menu bar is on a secondary screen (for example on
- * a monitor hooked up to a laptop), then this screen is screen 0 and
- * other monitors will be positioned according to the "secondary screen".
- * The main screen is the monitor that shows the window that is currently
- * active (has focus), the position of the menu bar does not have influence
- * on this!
- *
- * Upon start up and changes in the layout of screens, we calculate the
- * size of the GdkScreen root window that is needed to be able to place
- * all monitors in the root window. Once that size is known, we iterate
- * over the monitors and translate their Cocoa position to a position
- * in the root window of the GdkScreen. This happens below in the
- * function gdk_quartz_screen_calculate_layout().
- *
- * A Cocoa coordinate is always relative to the origin of the monitor
- * coordinate space. Such coordinates are mapped to their respective
- * position in the GdkScreen root window (_gdk_quartz_surface_xy_to_gdk_xy)
- * and vice versa (_gdk_quartz_surface_gdk_xy_to_xy). Both functions can
- * be found in gdksurface-quartz.c. Note that Cocoa coordinates can have
- * negative values (in case a monitor is located left or below of screen 0),
- * but GDK coordinates can *not*!
- */
-
-static void gdk_quartz_screen_dispose (GObject *object);
-static void gdk_quartz_screen_finalize (GObject *object);
-static void gdk_quartz_screen_calculate_layout (GdkQuartzScreen *screen);
-
-static void display_reconfiguration_callback (CGDirectDisplayID display,
- CGDisplayChangeSummaryFlags flags,
- void *userInfo);
-
-static gint get_mm_from_pixels (NSScreen *screen, int pixels);
-
-G_DEFINE_TYPE (GdkQuartzScreen, gdk_quartz_screen, G_TYPE_OBJECT);
-
-static void
-gdk_quartz_screen_init (GdkQuartzScreen *screen)
-{
- NSDictionary *dd = [[[NSScreen screens] objectAtIndex:0] deviceDescription];
- NSSize size = [[dd valueForKey:NSDeviceResolution] sizeValue];
-
- gdk_quartz_screen_calculate_layout (screen);
-
- CGDisplayRegisterReconfigurationCallback (display_reconfiguration_callback, screen);
-
- quartz_screen->emit_monitors_changed = FALSE;
-}
-
-static void
-gdk_quartz_screen_dispose (GObject *object)
-{
- GdkQuartzScreen *screen = GDK_QUARTZ_SCREEN (object);
-
- if (screen->screen_changed_id)
- {
- g_source_remove (screen->screen_changed_id);
- screen->screen_changed_id = 0;
- }
-
- CGDisplayRemoveReconfigurationCallback (display_reconfiguration_callback, screen);
-
- G_OBJECT_CLASS (gdk_quartz_screen_parent_class)->dispose (object);
-}
-
-static void
-gdk_quartz_screen_finalize (GObject *object)
-{
- G_OBJECT_CLASS (gdk_quartz_screen_parent_class)->finalize (object);
-}
-
-/* Protocol to build cleanly for OSX < 10.7 */
-@protocol ScaleFactor
-- (CGFloat) backingScaleFactor;
-@end
-
-static void
-gdk_quartz_screen_calculate_layout (GdkQuartzScreen *screen)
-{
- NSArray *array;
- int i;
- int max_x, max_y;
- GdkDisplay *display = screen->display;
- GdkQuartzDisplay *display_quartz = GDK_QUARTZ_DISPLAY (display);
-
- g_ptr_array_free (display_quartz->monitors, TRUE);
- display_quartz->monitors = g_ptr_array_new_with_free_func (g_object_unref);
-
- GDK_QUARTZ_ALLOC_POOL;
-
- array = [NSScreen screens];
-
- screen->width = 0;
- screen->height = 0;
- screen->min_x = 0;
- screen->min_y = 0;
- max_x = max_y = 0;
-
- /* We determine the minimum and maximum x and y coordinates
- * covered by the monitors. From this we can deduce the width
- * and height of the root screen.
- */
- for (i = 0; i < [array count]; i++)
- {
- GdkQuartzMonitor *monitor = g_object_new (GDK_TYPE_QUARTZ_MONITOR,
- "display", display,
- NULL);
- g_ptr_array_add (display_quartz->monitors, monitor);
- monitor->monitor_num = i;
-
- NSRect rect = [[array objectAtIndex:i] frame];
-
- screen->min_x = MIN (screen->min_x, rect.origin.x);
- max_x = MAX (max_x, rect.origin.x + rect.size.width);
-
- screen->min_y = MIN (screen->min_y, rect.origin.y);
- max_y = MAX (max_y, rect.origin.y + rect.size.height);
- }
-
- screen->width = max_x - screen->min_x;
- screen->height = max_y - screen->min_y;
-
- for (i = 0; i < [array count] ; i++)
- {
- NSScreen *nsscreen;
- NSRect rect;
- GdkMonitor *monitor;
-
- monitor = GDK_MONITOR(display_quartz->monitors->pdata[i]);
- nsscreen = [array objectAtIndex:i];
- rect = [nsscreen frame];
-
- monitor->geometry.x = rect.origin.x - screen->min_x;
- monitor->geometry.y
- = screen->height - (rect.origin.y + rect.size.height) + screen->min_y;
- monitor->geometry.width = rect.size.width;
- monitor->geometry.height = rect.size.height;
- if (gdk_quartz_osx_version() >= GDK_OSX_LION)
- monitor->scale_factor = [(id <ScaleFactor>) nsscreen backingScaleFactor];
- else
- monitor->scale_factor = 1;
- monitor->width_mm = get_mm_from_pixels(nsscreen, monitor->geometry.width);
- monitor->height_mm = get_mm_from_pixels(nsscreen, monitor->geometry.height);
- monitor->refresh_rate = 0; // unknown
- monitor->manufacturer = NULL; // unknown
- monitor->model = NULL; // unknown
- monitor->subpixel_layout = GDK_SUBPIXEL_LAYOUT_UNKNOWN; // unknown
- }
-
- GDK_QUARTZ_RELEASE_POOL;
-}
-
-void
-_gdk_quartz_screen_update_window_sizes (GdkQuartzScreen *screen)
-{
- GList *windows, *list;
-
- /* The size of the root window is so that it can contain all
- * monitors attached to this machine. The monitors are laid out
- * within this root window. We calculate the size of the root window
- * and the positions of the different monitors in gdkscreen-quartz.c.
- *
- * This data is updated when the monitor configuration is changed.
- */
-
- _gdk_root->x = 0;
- _gdk_root->y = 0;
- _gdk_root->abs_x = 0;
- _gdk_root->abs_y = 0;
-
- windows = get_toplevels ();
- for (list = windows; list; list = list->next)
- _gdk_quartz_surface_update_position (list->data);
-}
-
-static void
-process_display_reconfiguration (GdkQuartzScreen *screen)
-{
- gdk_quartz_screen_calculate_layout (screen);
-
- _gdk_quartz_screen_update_window_sizes (GDK_SCREEN (screen));
-}
-
-static gboolean
-screen_changed_idle (gpointer data)
-{
- GdkQuartzScreen *screen = data;
-
- process_display_reconfiguration (data);
-
- screen->screen_changed_id = 0;
-
- return FALSE;
-}
-
-static void
-display_reconfiguration_callback (CGDirectDisplayID display,
- CGDisplayChangeSummaryFlags flags,
- void *userInfo)
-{
- GdkQuartzScreen *screen = userInfo;
-
- if (flags & kCGDisplayBeginConfigurationFlag)
- {
- /* Ignore the begin configuration signal. */
- return;
- }
- else
- {
- /* We save information about the changes, so we can emit
- * ::monitors-changed when appropriate. This signal must be
- * emitted when the number, size of position of one of the
- * monitors changes.
- */
- if (flags & kCGDisplayMovedFlag
- || flags & kCGDisplayAddFlag
- || flags & kCGDisplayRemoveFlag
- || flags & kCGDisplayEnabledFlag
- || flags & kCGDisplayDisabledFlag)
- screen->emit_monitors_changed = TRUE;
-
- /* At this point Cocoa does not know about the new screen data
- * yet, so we delay our refresh into an idle handler.
- */
- if (!screen->screen_changed_id)
- {
- screen->screen_changed_id = g_idle_add (screen_changed_idle, screen);
- g_source_set_name_by_id (screen->screen_changed_id, "[gtk] screen_changed_idle");
- }
- }
-}
-
-static gint
-get_mm_from_pixels (NSScreen *screen, int pixels)
-{
- const float mm_per_inch = 25.4;
- NSDictionary *dd = [[[NSScreen screens] objectAtIndex:0] deviceDescription];
- NSSize size = [[dd valueForKey:NSDeviceResolution] sizeValue];
- float dpi = size.width;
- return (pixels / dpi) * mm_per_inch;
-}
-
-static void
-gdk_quartz_screen_class_init (GdkQuartzScreenClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- object_class->dispose = gdk_quartz_screen_dispose;
- object_class->finalize = gdk_quartz_screen_finalize;
-}
+++ /dev/null
-/* gdkscreen-quartz.h
- *
- * Copyright (C) 2009,2010 Kristian Rietveld <kris@gtk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __GDK_QUARTZ_SCREEN__
-#define __GDK_QUARTZ_SCREEN__
-
-G_BEGIN_DECLS
-
-struct _GdkQuartzScreen
-{
- GObject parent_instance;
-
- GdkDisplay *display;
-
- /* Origin of "root window" in Cocoa coordinates */
- gint min_x;
- gint min_y;
-
- gint width;
- gint height;
-
- guint screen_changed_id;
-
- guint emit_monitors_changed : 1;
-};
-
-struct _GdkQuartzScreenClass
-{
- GObjectClass parent_class;
-};
-
-G_END_DECLS
-
-#endif /* __GDK_QUARTZ_SCREEN__ */
+++ /dev/null
-/* gdkselection-quartz.c
- *
- * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
- * Copyright (C) 1998-2002 Tor Lillqvist
- * Copyright (C) 2005 Imendio AB
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-
-#include "gdkquartz.h"
-
-GdkAtom
-gdk_quartz_pasteboard_type_to_atom_libgtk_only (NSString *type)
-{
- if ([type isEqualToString:NSStringPboardType])
- return g_intern_static_string ("UTF8_STRING");
- else if ([type isEqualToString:NSTIFFPboardType])
- return g_intern_static_string ("image/tiff");
- else if ([type isEqualToString:NSColorPboardType])
- return g_intern_static_string ("application/x-color");
- else if ([type isEqualToString:NSURLPboardType])
- return g_intern_static_string ("text/uri-list");
- else
- return g_intern_string ([type UTF8String]);
-}
-
-NSString *
-gdk_quartz_target_to_pasteboard_type_libgtk_only (const char *target)
-{
- if (strcmp (target, "UTF8_STRING") == 0)
- return NSStringPboardType;
- else if (strcmp (target, "image/tiff") == 0)
- return NSTIFFPboardType;
- else if (strcmp (target, "application/x-color") == 0)
- return NSColorPboardType;
- else if (strcmp (target, "text/uri-list") == 0)
- return NSURLPboardType;
- else
- return [NSString stringWithUTF8String:target];
-}
-
-NSString *
-gdk_quartz_atom_to_pasteboard_type_libgtk_only (GdkAtom atom)
-{
- const char *target = (const char *)atom;
- NSString *ret = gdk_quartz_target_to_pasteboard_type_libgtk_only (target);
-
- return ret;
-}
+++ /dev/null
-/* gdksurface-quartz.c
- *
- * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
- * Copyright (C) 2005-2007 Imendio AB
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-
-#include <gdk/gdk.h>
-#include <gdk/gdkdeviceprivate.h>
-#include <gdk/gdkdisplayprivate.h>
-
-#include "gdksurfaceimpl.h"
-#include "gdkprivate-quartz.h"
-#include "gdkglcontext-quartz.h"
-#include "gdkquartzscreen.h"
-#include "gdkquartzcursor.h"
-
-#include <Carbon/Carbon.h>
-#include <AvailabilityMacros.h>
-
-#include <sys/time.h>
-#include <cairo-quartz.h>
-
-static gpointer parent_class;
-static gpointer root_window_parent_class;
-
-static GSList *update_nswindows;
-static gboolean in_process_all_updates = FALSE;
-
-static GSList *main_window_stack;
-
-void _gdk_quartz_surface_flush (GdkSurfaceImplQuartz *surface_impl);
-
-typedef struct
-{
- gint x, y;
- gint width, height;
- GdkWMDecoration decor;
-} FullscreenSavedGeometry;
-
-
-#ifndef AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
-static FullscreenSavedGeometry *get_fullscreen_geometry (GdkSurface *window);
-#endif
-
-#define FULLSCREEN_DATA "fullscreen-data"
-
-static void update_toplevel_order (void);
-static void clear_toplevel_order (void);
-
-#define SURFACE_IS_TOPLEVEL(window) TRUE
-
-/*
- * GdkQuartzSurface
- */
-
-struct _GdkQuartzSurface
-{
- GdkSurface parent;
-};
-
-struct _GdkQuartzSurfaceClass
-{
- GdkSurfaceClass parent_class;
-};
-
-G_DEFINE_TYPE (GdkQuartzSurface, gdk_quartz_surface, GDK_TYPE_SURFACE);
-
-static void
-gdk_quartz_surface_class_init (GdkQuartzSurfaceClass *quartz_surface_class)
-{
-}
-
-static void
-gdk_quartz_surface_init (GdkQuartzSurface *quartz_surface)
-{
-}
-
-
-/*
- * GdkQuartzSurfaceImpl
- */
-
-NSView *
-gdk_quartz_surface_get_nsview (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window))
- return NULL;
-
- return ((GdkSurfaceImplQuartz *)window->impl)->view;
-}
-
-NSWindow *
-gdk_quartz_surface_get_nswindow (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window))
- return NULL;
-
- return ((GdkSurfaceImplQuartz *)window->impl)->toplevel;
-}
-
-static CGContextRef
-gdk_surface_impl_quartz_get_context (GdkSurfaceImplQuartz *surface_impl,
- gboolean antialias)
-{
- CGContextRef cg_context;
- CGSize scale;
-
- if (GDK_SURFACE_DESTROYED (surface_impl->wrapper))
- return NULL;
-
- /* Lock focus when not called as part of a drawRect call. This
- * is needed when called from outside "real" expose events, for
- * example for synthesized expose events when realizing windows
- * and for widgets that send fake expose events like the arrow
- * buttons in spinbuttons or the position marker in rulers.
- */
- if (surface_impl->in_paint_rect_count == 0)
- {
- if (![surface_impl->view lockFocusIfCanDraw])
- return NULL;
- }
- if (gdk_quartz_osx_version () < GDK_OSX_YOSEMITE)
- cg_context = [[NSGraphicsContext currentContext] graphicsPort];
- else
- cg_context = [[NSGraphicsContext currentContext] CGContext];
- if (!cg_context)
- return NULL;
- CGContextSaveGState (cg_context);
- CGContextSetAllowsAntialiasing (cg_context, antialias);
-
- /* Undo the default scaling transform, since we apply our own
- * in gdk_quartz_ref_cairo_surface () */
- scale = CGContextConvertSizeToDeviceSpace (cg_context,
- CGSizeMake (1.0, 1.0));
- CGContextScaleCTM (cg_context, 1.0 / scale.width, 1.0 / scale.height);
-
- return cg_context;
-}
-
-static void
-gdk_surface_impl_quartz_release_context (GdkSurfaceImplQuartz *surface_impl,
- CGContextRef cg_context)
-{
- CGContextRestoreGState (cg_context);
- CGContextSetAllowsAntialiasing (cg_context, TRUE);
-
- /* See comment in gdk_quartz_surface_get_context(). */
- if (surface_impl->in_paint_rect_count == 0)
- {
- _gdk_quartz_surface_flush (surface_impl);
- [surface_impl->view unlockFocus];
- }
-}
-
-static void
-check_grab_destroy (GdkSurface *window)
-{
- GList *devices = NULL, *l;
- GdkDisplay *display = gdk_surface_get_display (window);
- GdkSeat *seat;
-
- seat = gdk_display_get_default_seat (display);
-
- devices = g_list_prepend (devices, gdk_seat_get_keyboard (seat));
- devices = g_list_prepend (devices, gdk_seat_get_pointer (seat));
-
- for (l = devices; l; l = l->next)
- {
- GdkDeviceGrabInfo *grab;
-
- grab = _gdk_display_get_last_device_grab (display, l->data);
- if (grab && grab->native_surface == window)
- {
- /* Serials are always 0 in quartz, but for clarity: */
- grab->serial_end = grab->serial_start;
- grab->implicit_ungrab = TRUE;
- }
- }
-
- g_list_free (devices);
-}
-
-static void
-gdk_surface_impl_quartz_finalize (GObject *object)
-{
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (object);
-
- check_grab_destroy (GDK_SURFACE_IMPL_QUARTZ (object)->wrapper);
-
- if (impl->transient_for)
- g_object_unref (impl->transient_for);
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-/* Help preventing "beam sync penalty" where CG makes all graphics code
- * block until the next vsync if we try to flush (including call display on
- * a view) too often. We do this by limiting the manual flushing done
- * outside of expose calls to less than some frequency when measured over
- * the last 4 flushes. This is a bit arbitray, but seems to make it possible
- * for some quick manual flushes (such as gtkruler or gimp’s marching ants)
- * without hitting the max flush frequency.
- *
- * If drawable NULL, no flushing is done, only registering that a flush was
- * done externally.
- */
-void
-_gdk_quartz_surface_flush (GdkSurfaceImplQuartz *surface_impl)
-{
- static struct timeval prev_tv;
- static gint intervals[4];
- static gint index;
- struct timeval tv;
- gint ms;
-
- gettimeofday (&tv, NULL);
- ms = (tv.tv_sec - prev_tv.tv_sec) * 1000 + (tv.tv_usec - prev_tv.tv_usec) / 1000;
- intervals[index++ % 4] = ms;
-
- if (surface_impl)
- {
- ms = intervals[0] + intervals[1] + intervals[2] + intervals[3];
-
- /* ~25Hz on average. */
- if (ms > 4*40)
- {
- if (surface_impl)
- [surface_impl->toplevel flushWindow];
-
- prev_tv = tv;
- }
- }
- else
- prev_tv = tv;
-}
-
-static cairo_user_data_key_t gdk_quartz_cairo_key;
-
-typedef struct {
- GdkSurfaceImplQuartz *surface_impl;
- CGContextRef cg_context;
-} GdkQuartzCairoSurfaceData;
-
-static void
-gdk_quartz_cairo_surface_destroy (void *data)
-{
- GdkQuartzCairoSurfaceData *surface_data = data;
-
- surface_data->surface_impl->cairo_surface = NULL;
-
- gdk_quartz_surface_release_context (surface_data->surface_impl,
- surface_data->cg_context);
-
- g_free (surface_data);
-}
-
-static cairo_surface_t *
-gdk_quartz_create_cairo_surface (GdkSurfaceImplQuartz *impl,
- int width,
- int height)
-{
- CGContextRef cg_context;
- GdkQuartzCairoSurfaceData *surface_data;
- cairo_surface_t *surface;
-
- cg_context = gdk_quartz_surface_get_context (impl, TRUE);
-
- surface_data = g_new (GdkQuartzCairoSurfaceData, 1);
- surface_data->surface_impl = impl;
- surface_data->cg_context = cg_context;
-
- if (cg_context)
- surface = cairo_quartz_surface_create_for_cg_context (cg_context,
- width, height);
- else
- surface = cairo_quartz_surface_create(CAIRO_FORMAT_ARGB32, width, height);
-
- cairo_surface_set_user_data (surface, &gdk_quartz_cairo_key,
- surface_data,
- gdk_quartz_cairo_surface_destroy);
-
- return surface;
-}
-
-static cairo_surface_t *
-gdk_quartz_ref_cairo_surface (GdkSurface *window)
-{
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (GDK_SURFACE_DESTROYED (window))
- return NULL;
-
- if (!impl->cairo_surface)
- {
- gint scale = gdk_surface_get_scale_factor (impl->wrapper);
-
- impl->cairo_surface =
- gdk_quartz_create_cairo_surface (impl,
- gdk_surface_get_width (impl->wrapper) * scale,
- gdk_surface_get_height (impl->wrapper) * scale);
-
- cairo_surface_set_device_scale (impl->cairo_surface, scale, scale);
- }
- else
- cairo_surface_reference (impl->cairo_surface);
-
- return impl->cairo_surface;
-}
-
-static void
-gdk_surface_impl_quartz_init (GdkSurfaceImplQuartz *impl)
-{
- impl->type_hint = GDK_SURFACE_TYPE_HINT_NORMAL;
-}
-
-static gboolean
-gdk_surface_impl_quartz_begin_paint (GdkSurface *window)
-{
- return FALSE;
-}
-
-static void
-gdk_quartz_surface_set_needs_display_in_region (GdkSurface *window,
- cairo_region_t *region)
-{
- GdkSurfaceImplQuartz *impl;
- int i, n_rects;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (!impl->needs_display_region)
- impl->needs_display_region = cairo_region_create ();
-
- cairo_region_union (impl->needs_display_region, region);
-
- n_rects = cairo_region_num_rectangles (region);
- for (i = 0; i < n_rects; i++)
- {
- cairo_rectangle_int_t rect;
- cairo_region_get_rectangle (region, i, &rect);
- [impl->view setNeedsDisplayInRect:NSMakeRect (rect.x, rect.y,
- rect.width, rect.height)];
- }
-}
-
-void
-_gdk_quartz_surface_process_updates_recurse (GdkSurface *window,
- cairo_region_t *region)
-{
- /* Make sure to only flush each toplevel at most once if we're called
- * from process_all_updates.
- */
- if (in_process_all_updates)
- {
- GdkSurface *toplevel;
-
- toplevel = gdk_surface_get_toplevel (window);
- if (toplevel && SURFACE_IS_TOPLEVEL (toplevel))
- {
- GdkSurfaceImplQuartz *toplevel_impl;
- NSWindow *nswindow;
-
- toplevel_impl = (GdkSurfaceImplQuartz *)toplevel->impl;
- nswindow = toplevel_impl->toplevel;
-
- /* In theory, we could skip the flush disabling, since we only
- * have one NSView.
- */
- if (nswindow && ![nswindow isFlushWindowDisabled])
- {
- [nswindow retain];
- [nswindow disableFlushWindow];
- update_nswindows = g_slist_prepend (update_nswindows, nswindow);
- }
- }
- }
-
- if (SURFACE_IS_TOPLEVEL (window))
- gdk_quartz_surface_set_needs_display_in_region (window, region);
- else
- _gdk_surface_process_updates_recurse (window, region);
-
- /* NOTE: I'm not sure if we should displayIfNeeded here. It slows down a
- * lot (since it triggers the beam syncing) and things seem to work
- * without it.
- */
-}
-
-static const gchar *
-get_default_title (void)
-{
- const char *title;
-
- title = g_get_application_name ();
- if (!title)
- title = g_get_prgname ();
-
- return title;
-}
-
-static void
-get_ancestor_coordinates_from_child (GdkSurface *child_window,
- gint child_x,
- gint child_y,
- GdkSurface *ancestor_window,
- gint *ancestor_x,
- gint *ancestor_y)
-{
- while (child_window != ancestor_window)
- {
- child_x += child_window->x;
- child_y += child_window->y;
-
- child_window = child_window->parent;
- }
-
- *ancestor_x = child_x;
- *ancestor_y = child_y;
-}
-
-void
-_gdk_quartz_surface_debug_highlight (GdkSurface *window, gint number)
-{
- gint x, y;
- gint gx, gy;
- GdkSurface *toplevel;
- gint tx, ty;
- static NSWindow *debug_window[10];
- static NSRect old_rect[10];
- NSRect rect;
- NSColor *color;
-
- g_return_if_fail (number >= 0 && number <= 9);
-
- if (window == _gdk_root)
- return;
-
- if (window == NULL)
- {
- if (debug_window[number])
- [debug_window[number] close];
- debug_window[number] = NULL;
-
- return;
- }
-
- toplevel = gdk_surface_get_toplevel (window);
- get_ancestor_coordinates_from_child (window, 0, 0, toplevel, &x, &y);
-
- gdk_surface_get_origin (toplevel, &tx, &ty);
- x += tx;
- y += ty;
-
- _gdk_quartz_surface_gdk_xy_to_xy (x, y + window->height,
- &gx, &gy);
-
- rect = NSMakeRect (gx, gy, window->width, window->height);
-
- if (debug_window[number] && NSEqualRects (rect, old_rect[number]))
- return;
-
- old_rect[number] = rect;
-
- if (debug_window[number])
- [debug_window[number] close];
-
- debug_window[number] = [[NSWindow alloc] initWithContentRect:rect
- styleMask:NSBorderlessWindowMask
- backing:NSBackingStoreBuffered
- defer:NO];
-
- switch (number)
- {
- case 0:
- color = [NSColor redColor];
- break;
- case 1:
- color = [NSColor blueColor];
- break;
- case 2:
- color = [NSColor greenColor];
- break;
- case 3:
- color = [NSColor yellowColor];
- break;
- case 4:
- color = [NSColor brownColor];
- break;
- case 5:
- color = [NSColor purpleColor];
- break;
- default:
- color = [NSColor blackColor];
- break;
- }
-
- [debug_window[number] setBackgroundColor:color];
- [debug_window[number] setAlphaValue:0.4];
- [debug_window[number] setOpaque:NO];
- [debug_window[number] setReleasedWhenClosed:YES];
- [debug_window[number] setIgnoresMouseEvents:YES];
- [debug_window[number] setLevel:NSFloatingWindowLevel];
-
- [debug_window[number] orderFront:nil];
-}
-
-gboolean
-_gdk_quartz_surface_is_ancestor (GdkSurface *ancestor,
- GdkSurface *window)
-{
- if (ancestor == NULL || window == NULL)
- return FALSE;
-
- return (gdk_surface_get_parent (window) == ancestor ||
- _gdk_quartz_surface_is_ancestor (ancestor,
- gdk_surface_get_parent (window)));
-}
-
-
-/* See notes on top of gdkscreen-quartz.c */
-void
-_gdk_quartz_surface_gdk_xy_to_xy (gint gdk_x,
- gint gdk_y,
- gint *ns_x,
- gint *ns_y)
-{
- GdkQuartzScreen *screen_quartz = GDK_QUARTZ_SCREEN (_gdk_screen);
-
- if (ns_y)
- *ns_y = screen_quartz->height - gdk_y + screen_quartz->min_y;
-
- if (ns_x)
- *ns_x = gdk_x + screen_quartz->min_x;
-}
-
-void
-_gdk_quartz_surface_xy_to_gdk_xy (gint ns_x,
- gint ns_y,
- gint *gdk_x,
- gint *gdk_y)
-{
- GdkQuartzScreen *screen_quartz = GDK_QUARTZ_SCREEN (_gdk_screen);
-
- if (gdk_y)
- *gdk_y = screen_quartz->height - ns_y + screen_quartz->min_y;
-
- if (gdk_x)
- *gdk_x = ns_x - screen_quartz->min_x;
-}
-
-void
-_gdk_quartz_surface_nspoint_to_gdk_xy (NSPoint point,
- gint *x,
- gint *y)
-{
- _gdk_quartz_surface_xy_to_gdk_xy (point.x, point.y,
- x, y);
-}
-
-static GdkSurface *
-find_child_window_helper (GdkSurface *window,
- gint x,
- gint y,
- gint x_offset,
- gint y_offset,
- gboolean get_toplevel)
-{
- GdkSurfaceImplQuartz *impl;
- GList *l;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (window == _gdk_root)
- update_toplevel_order ();
-
- for (l = impl->sorted_children; l; l = l->next)
- {
- GdkSurface *child = l->data;
- GdkSurfaceImplQuartz *child_impl = GDK_SURFACE_IMPL_QUARTZ (child->impl);
- int temp_x, temp_y;
-
- if (!GDK_SURFACE_IS_MAPPED (child))
- continue;
-
- temp_x = x_offset + child->x;
- temp_y = y_offset + child->y;
-
- /* Special-case the root window. We have to include the title
- * bar in the checks, otherwise the window below the title bar
- * will be found i.e. events punch through. (If we can find a
- * better way to deal with the events in gdkevents-quartz, this
- * might not be needed.)
- */
- if (window == _gdk_root)
- {
- NSRect frame = NSMakeRect (0, 0, 100, 100);
- NSRect content;
- NSUInteger mask;
- int titlebar_height;
-
- mask = [child_impl->toplevel styleMask];
-
- /* Get the title bar height. */
- content = [NSWindow contentRectForFrameRect:frame
- styleMask:mask];
- titlebar_height = frame.size.height - content.size.height;
-
- if (titlebar_height > 0 &&
- x >= temp_x && y >= temp_y - titlebar_height &&
- x < temp_x + child->width && y < temp_y)
- {
- /* The root means "unknown" i.e. a window not managed by
- * GDK.
- */
- return (GdkSurface *)_gdk_root;
- }
- }
-
- if ((!get_toplevel || (get_toplevel && window == _gdk_root)) &&
- x >= temp_x && y >= temp_y &&
- x < temp_x + child->width && y < temp_y + child->height)
- {
- /* Look for child windows. */
- return find_child_window_helper (l->data,
- x, y,
- temp_x, temp_y,
- get_toplevel);
- }
- }
-
- return window;
-}
-
-/* Given a GdkSurface and coordinates relative to it, returns the
- * innermost subwindow that contains the point. If the coordinates are
- * outside the passed in window, NULL is returned.
- */
-GdkSurface *
-_gdk_quartz_surface_find_child (GdkSurface *window,
- gint x,
- gint y,
- gboolean get_toplevel)
-{
- if (x >= 0 && y >= 0 && x < window->width && y < window->height)
- return find_child_window_helper (window, x, y, 0, 0, get_toplevel);
-
- return NULL;
-}
-
-
-void
-_gdk_quartz_surface_did_become_main (GdkSurface *window)
-{
- main_window_stack = g_slist_remove (main_window_stack, window);
-
- if (window->surface_type != GDK_SURFACE_TEMP)
- main_window_stack = g_slist_prepend (main_window_stack, window);
-
- clear_toplevel_order ();
-}
-
-void
-_gdk_quartz_surface_did_resign_main (GdkSurface *window)
-{
- GdkSurface *new_window = NULL;
-
- if (main_window_stack)
- new_window = main_window_stack->data;
- else
- {
- GList *toplevels;
-
- toplevels = get_toplevels ();
- if (toplevels)
- new_window = toplevels->data;
- }
-
- if (new_window &&
- new_window != window &&
- GDK_SURFACE_IS_MAPPED (new_window) &&
- SURFACE_IS_TOPLEVEL (new_window))
- {
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (new_window->impl);
-
- [impl->toplevel makeKeyAndOrderFront:impl->toplevel];
- }
-
- clear_toplevel_order ();
-}
-
-static NSScreen *
-get_nsscreen_for_point (gint x, gint y)
-{
- int i;
- NSArray *screens;
- NSScreen *screen = NULL;
-
- GDK_QUARTZ_ALLOC_POOL;
-
- screens = [NSScreen screens];
-
- for (i = 0; i < [screens count]; i++)
- {
- NSRect rect = [[screens objectAtIndex:i] frame];
-
- if (x >= rect.origin.x && x <= rect.origin.x + rect.size.width &&
- y >= rect.origin.y && y <= rect.origin.y + rect.size.height)
- {
- screen = [screens objectAtIndex:i];
- break;
- }
- }
-
- GDK_QUARTZ_RELEASE_POOL;
-
- return screen;
-}
-
-void
-_gdk_quartz_display_create_surface_impl (GdkDisplay *display,
- GdkSurface *window,
- GdkSurface *real_parent)
-{
- GdkSurfaceImplQuartz *impl;
- GdkSurfaceImplQuartz *parent_impl;
-
- GDK_QUARTZ_ALLOC_POOL;
-
- impl = g_object_new (GDK_TYPE_SURFACE_IMPL_QUARTZ, NULL);
- window->impl = GDK_SURFACE_IMPL (impl);
- impl->wrapper = window;
-
- parent_impl = GDK_SURFACE_IMPL_QUARTZ (window->parent->impl);
-
- switch (window->surface_type)
- {
- case GDK_SURFACE_TOPLEVEL:
- case GDK_SURFACE_TEMP:
- if (GDK_SURFACE_TYPE (window->parent) != GDK_SURFACE_ROOT)
- {
- /* The common code warns for this case */
- parent_impl = GDK_SURFACE_IMPL_QUARTZ (_gdk_root->impl);
- }
- }
-
- /* Maintain the z-ordered list of children. */
- if (window->parent != _gdk_root)
- parent_impl->sorted_children = g_list_prepend (parent_impl->sorted_children, window);
- else
- clear_toplevel_order ();
-
- impl->view = NULL;
-
- switch (window->surface_type)
- {
- case GDK_SURFACE_TOPLEVEL:
- case GDK_SURFACE_TEMP:
- {
- NSScreen *screen;
- NSRect screen_rect;
- NSRect content_rect;
- NSUInteger style_mask;
- int nx, ny;
-
- /* initWithContentRect will place on the mainScreen by default.
- * We want to select the screen to place on ourselves. We need
- * to find the screen the window will be on and correct the
- * content_rect coordinates to be relative to that screen.
- */
- _gdk_quartz_surface_gdk_xy_to_xy (window->x, window->y, &nx, &ny);
-
- screen = get_nsscreen_for_point (nx, ny);
- screen_rect = [screen frame];
- nx -= screen_rect.origin.x;
- ny -= screen_rect.origin.y;
-
- content_rect = NSMakeRect (nx, ny - window->height,
- window->width,
- window->height);
-
- if (window->surface_type == GDK_SURFACE_TEMP)
- {
- style_mask = NSBorderlessWindowMask;
- }
- else
- {
- style_mask = (NSTitledWindowMask |
- NSClosableWindowMask |
- NSMiniaturizableWindowMask |
- NSResizableWindowMask);
- }
-
- impl->toplevel = [[GdkQuartzNSWindow alloc] initWithContentRect:content_rect
- styleMask:style_mask
- backing:NSBackingStoreBuffered
- defer:NO
- screen:screen];
-
- gdk_surface_set_title (window, get_default_title ());
-
- [impl->toplevel setOpaque:NO];
- [impl->toplevel setBackgroundColor:[NSColor clearColor]];
-
- content_rect.origin.x = 0;
- content_rect.origin.y = 0;
-
- impl->view = [[GdkQuartzView alloc] initWithFrame:content_rect];
- [impl->view setGdkSurface:window];
- [impl->toplevel setContentView:impl->view];
- [impl->view release];
- }
- break;
-
- default:
- g_assert_not_reached ();
- }
-
- GDK_QUARTZ_RELEASE_POOL;
-}
-
-void
-_gdk_quartz_surface_update_position (GdkSurface *window)
-{
- NSRect frame_rect;
- NSRect content_rect;
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- GDK_QUARTZ_ALLOC_POOL;
-
- frame_rect = [impl->toplevel frame];
- content_rect = [impl->toplevel contentRectForFrameRect:frame_rect];
-
- _gdk_quartz_surface_xy_to_gdk_xy (content_rect.origin.x,
- content_rect.origin.y + content_rect.size.height,
- &window->x, &window->y);
-
-
- GDK_QUARTZ_RELEASE_POOL;
-}
-
-void
-_gdk_quartz_surface_init_windowing (GdkDisplay *display)
-{
- GdkSurfaceImplQuartz *impl;
-
- g_assert (_gdk_root == NULL);
-
- _gdk_root = _gdk_display_create_window (display);
-
- _gdk_root->impl = g_object_new (_gdk_root_surface_impl_quartz_get_type (), NULL);
- _gdk_root->impl_surface = _gdk_root;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (_gdk_root->impl);
-
- _gdk_quartz_screen_update_window_sizes (screen);
-
- _gdk_root->state = 0; /* We don't want GDK_SURFACE_STATE_WITHDRAWN here */
- _gdk_root->surface_type = GDK_SURFACE_ROOT;
- _gdk_root->viewable = TRUE;
-
- impl->wrapper = _gdk_root;
-}
-
-static void
-gdk_quartz_surface_destroy (GdkSurface *window,
- gboolean recursing,
- gboolean foreign_destroy)
-{
- GdkSurfaceImplQuartz *impl;
- GdkSurface *parent;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- main_window_stack = g_slist_remove (main_window_stack, window);
-
- g_list_free (impl->sorted_children);
- impl->sorted_children = NULL;
-
- parent = window->parent;
- if (parent)
- {
- GdkSurfaceImplQuartz *parent_impl = GDK_SURFACE_IMPL_QUARTZ (parent->impl);
-
- parent_impl->sorted_children = g_list_remove (parent_impl->sorted_children, window);
- }
-
- if (impl->cairo_surface)
- {
- cairo_surface_finish (impl->cairo_surface);
- cairo_surface_set_user_data (impl->cairo_surface, &gdk_quartz_cairo_key,
- NULL, NULL);
- impl->cairo_surface = NULL;
- }
-
- if (!recursing && !foreign_destroy)
- {
- GDK_QUARTZ_ALLOC_POOL;
-
- if (impl->toplevel)
- [impl->toplevel close];
- else if (impl->view)
- [impl->view removeFromSuperview];
-
- GDK_QUARTZ_RELEASE_POOL;
- }
-}
-
-/* FIXME: This might be possible to simplify with client-side windows. Also
- * note that already_mapped is not used yet, see the x11 backend.
-*/
-static void
-gdk_surface_quartz_show (GdkSurface *window, gboolean already_mapped)
-{
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
- gboolean focus_on_map;
-
- GDK_QUARTZ_ALLOC_POOL;
-
- if (!GDK_SURFACE_IS_MAPPED (window))
- focus_on_map = window->focus_on_map;
- else
- focus_on_map = TRUE;
-
- if (SURFACE_IS_TOPLEVEL (window) && impl->toplevel)
- {
- gboolean make_key;
-
- make_key = (window->accept_focus && focus_on_map &&
- window->surface_type != GDK_SURFACE_TEMP);
-
- [(GdkQuartzNSWindow*)impl->toplevel showAndMakeKey:make_key];
- clear_toplevel_order ();
-
- _gdk_quartz_events_send_map_event (window);
- }
- else
- {
- [impl->view setHidden:NO];
- }
-
- [impl->view setNeedsDisplay:YES];
-
- gdk_synthesize_surface_state (window, GDK_SURFACE_STATE_WITHDRAWN, 0);
-
- if (window->state & GDK_SURFACE_STATE_MAXIMIZED)
- gdk_surface_maximize (window);
-
- if (window->state & GDK_SURFACE_STATE_MINIMIZED)
- gdk_surface_minimize (window);
-
- if (impl->transient_for && !GDK_SURFACE_DESTROYED (impl->transient_for))
- _gdk_quartz_surface_attach_to_parent (window);
-
- GDK_QUARTZ_RELEASE_POOL;
-}
-
-/* Temporarily unsets the parent window, if the window is a
- * transient.
- */
-void
-_gdk_quartz_surface_detach_from_parent (GdkSurface *window)
-{
- GdkSurfaceImplQuartz *impl;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- g_return_if_fail (impl->toplevel != NULL);
-
- if (impl->transient_for && !GDK_SURFACE_DESTROYED (impl->transient_for))
- {
- GdkSurfaceImplQuartz *parent_impl;
-
- parent_impl = GDK_SURFACE_IMPL_QUARTZ (impl->transient_for->impl);
- [parent_impl->toplevel removeChildWindow:impl->toplevel];
- clear_toplevel_order ();
- }
-}
-
-/* Re-sets the parent window, if the window is a transient. */
-void
-_gdk_quartz_surface_attach_to_parent (GdkSurface *window)
-{
- GdkSurfaceImplQuartz *impl;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- g_return_if_fail (impl->toplevel != NULL);
-
- if (impl->transient_for && !GDK_SURFACE_DESTROYED (impl->transient_for))
- {
- GdkSurfaceImplQuartz *parent_impl;
-
- parent_impl = GDK_SURFACE_IMPL_QUARTZ (impl->transient_for->impl);
- [parent_impl->toplevel addChildWindow:impl->toplevel ordered:NSWindowAbove];
- clear_toplevel_order ();
- }
-}
-
-void
-gdk_surface_quartz_hide (GdkSurface *window)
-{
- GdkSurfaceImplQuartz *impl;
-
- /* Make sure we're not stuck in fullscreen mode. */
-#ifndef AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
- if (get_fullscreen_geometry (window))
- SetSystemUIMode (kUIModeNormal, 0);
-#endif
-
- _gdk_surface_clear_update_area (window);
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (SURFACE_IS_TOPLEVEL (window))
- {
- /* Update main window. */
- main_window_stack = g_slist_remove (main_window_stack, window);
- if ([NSApp mainWindow] == impl->toplevel)
- _gdk_quartz_surface_did_resign_main (window);
-
- if (impl->transient_for)
- _gdk_quartz_surface_detach_from_parent (window);
-
- [(GdkQuartzNSWindow*)impl->toplevel hide];
- }
- else if (impl->view)
- {
- [impl->view setHidden:YES];
- }
-}
-
-void
-gdk_surface_quartz_withdraw (GdkSurface *window)
-{
- gdk_surface_hide (window);
-}
-
-static void
-move_resize_window_internal (GdkSurface *window,
- gint x,
- gint y,
- gint width,
- gint height)
-{
- GdkSurfaceImplQuartz *impl;
- GdkRectangle old_visible;
- GdkRectangle new_visible;
- GdkRectangle scroll_rect;
- cairo_region_t *old_region;
- cairo_region_t *expose_region;
- NSSize delta;
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if ((x == -1 || (x == window->x)) &&
- (y == -1 || (y == window->y)) &&
- (width == -1 || (width == window->width)) &&
- (height == -1 || (height == window->height)))
- {
- return;
- }
-
- if (!impl->toplevel)
- {
- /* The previously visible area of this window in a coordinate
- * system rooted at the origin of this window.
- */
- old_visible.x = -window->x;
- old_visible.y = -window->y;
-
- old_visible.width = window->width;
- old_visible.height = window->height;
- }
-
- if (x != -1)
- {
- delta.width = x - window->x;
- window->x = x;
- }
- else
- {
- delta.width = 0;
- }
-
- if (y != -1)
- {
- delta.height = y - window->y;
- window->y = y;
- }
- else
- {
- delta.height = 0;
- }
-
- if (width != -1)
- window->width = width;
-
- if (height != -1)
- window->height = height;
-
- GDK_QUARTZ_ALLOC_POOL;
-
- if (impl->toplevel)
- {
- NSRect content_rect;
- NSRect frame_rect;
- gint gx, gy;
-
- _gdk_quartz_surface_gdk_xy_to_xy (window->x, window->y + window->height,
- &gx, &gy);
-
- content_rect = NSMakeRect (gx, gy, window->width, window->height);
-
- frame_rect = [impl->toplevel frameRectForContentRect:content_rect];
- [impl->toplevel setFrame:frame_rect display:YES];
- }
- else
- {
- NSRect nsrect;
-
- nsrect = NSMakeRect (window->x, window->y, window->width, window->height);
-
- /* The newly visible area of this window in a coordinate
- * system rooted at the origin of this window.
- */
- new_visible.x = -window->x;
- new_visible.y = -window->y;
- new_visible.width = old_visible.width; /* parent has not changed size */
- new_visible.height = old_visible.height; /* parent has not changed size */
-
- expose_region = cairo_region_create_rectangle (&new_visible);
- old_region = cairo_region_create_rectangle (&old_visible);
- cairo_region_subtract (expose_region, old_region);
-
- /* Determine what (if any) part of the previously visible
- * part of the window can be copied without a redraw
- */
- scroll_rect = old_visible;
- scroll_rect.x -= delta.width;
- scroll_rect.y -= delta.height;
- gdk_rectangle_intersect (&scroll_rect, &old_visible, &scroll_rect);
-
- if (!cairo_region_is_empty (expose_region))
- {
- if (scroll_rect.width != 0 && scroll_rect.height != 0)
- {
- [impl->view scrollRect:NSMakeRect (scroll_rect.x,
- scroll_rect.y,
- scroll_rect.width,
- scroll_rect.height)
- by:delta];
- }
-
- [impl->view setFrame:nsrect];
-
- gdk_quartz_surface_set_needs_display_in_region (window, expose_region);
- }
- else
- {
- [impl->view setFrame:nsrect];
- [impl->view setNeedsDisplay:YES];
- }
-
- cairo_region_destroy (expose_region);
- cairo_region_destroy (old_region);
- }
-
- GDK_QUARTZ_RELEASE_POOL;
-}
-
-static inline void
-window_quartz_move (GdkSurface *window,
- gint x,
- gint y)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (window->state & GDK_SURFACE_STATE_FULLSCREEN)
- return;
-
- move_resize_window_internal (window, x, y, -1, -1);
-}
-
-static inline void
-window_quartz_resize (GdkSurface *window,
- gint width,
- gint height)
-{
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (window->state & GDK_SURFACE_STATE_FULLSCREEN)
- return;
-
- if (width < 1)
- width = 1;
- if (height < 1)
- height = 1;
-
- move_resize_window_internal (window, -1, -1, width, height);
-}
-
-static inline void
-window_quartz_move_resize (GdkSurface *window,
- gint x,
- gint y,
- gint width,
- gint height)
-{
- if (width < 1)
- width = 1;
- if (height < 1)
- height = 1;
-
- move_resize_window_internal (window, x, y, width, height);
-}
-
-static void
-gdk_surface_quartz_toplevel_resize (GdkSurface *surface,
- gint width,
- gint height)
-{
- window_quartz_resize (window, width, height);
-}
-
-static void
-gdk_quartz_surface_layout_popup (GdkSurface *surface,
- int width,
- int height,
- GdkPopupLayout *layout)
-{
- GdkRectangle final_rect;
- int x, y;
-
- gdk_surface_layout_popup_helper (surface,
- width,
- height,
- layout,
- &final_rect);
-
- gdk_surface_get_origin (surface->parent, &x, &y);
- x += final_rect.x;
- y += final_rect.y;
-
- if (final_rect.width != surface->width ||
- final_rect.height != surface->height)
- {
- move_resize_window_internal (surface,
- x,
- y,
- final_rect.width,
- final_rect.height);
- }
- else
- {
- window_quartz_move (surface, x, y);
- }
-}
-
-static void
-show_popup (GdkSurface *surface)
-{
- gdk_surface_raise (surface);
- gdk_synthesize_surface_state (surface, GDK_SURFACE_STATE_WITHDRAWN, 0);
- _gdk_surface_update_viewable (surface);
- gdk_quartz_surface_show (surface, FALSE);
- gdk_surface_invalidate_rect (surface, NULL);
-}
-
-static void
-show_grabbing_popup (GdkSeat *seat,
- GdkSurface *surface,
- gpointer user_data)
-{
- show_popup (surface);
-}
-
-static gboolean
-gdk_quartz_surface_present_popup (GdkSurface *surface,
- int width,
- int height,
- GdkPopupLayout *layout)
-{
- gdk_quartz_surface_layout_popup (surface, width, height, layout);
-
- if (GDK_SURFACE_IS_MAPPED (surface))
- return TRUE;
-
- if (surface->autohide)
- {
- gdk_seat_grab (gdk_display_get_default_seat (surface->display),
- surface,
- GDK_SEAT_CAPABILITY_ALL,
- TRUE,
- NULL, NULL,
- show_grabbing_popup, NULL);
- }
- else
- {
- show_popup (surface);
- }
-
- return GDK_SURFACE_IS_MAPPED (surface);
-}
-
-/* Get the toplevel ordering from NSApp and update our own list. We do
- * this on demand since the NSApp’s list is not up to date directly
- * after we get windowDidBecomeMain.
- */
-static void
-update_toplevel_order (void)
-{
- GdkSurfaceImplQuartz *root_impl;
- NSEnumerator *enumerator;
- id nswindow;
- GList *toplevels = NULL;
-
- root_impl = GDK_SURFACE_IMPL_QUARTZ (_gdk_root->impl);
-
- if (root_impl->sorted_children)
- return;
-
- GDK_QUARTZ_ALLOC_POOL;
-
- enumerator = [[NSApp orderedWindows] objectEnumerator];
- while ((nswindow = [enumerator nextObject]))
- {
- GdkSurface *window;
-
- if (![[nswindow contentView] isKindOfClass:[GdkQuartzView class]])
- continue;
-
- window = [(GdkQuartzView *)[nswindow contentView] gdkSurface];
- toplevels = g_list_prepend (toplevels, window);
- }
-
- GDK_QUARTZ_RELEASE_POOL;
-
- root_impl->sorted_children = g_list_reverse (toplevels);
-}
-
-static void
-clear_toplevel_order (void)
-{
- GdkSurfaceImplQuartz *root_impl;
-
- root_impl = GDK_SURFACE_IMPL_QUARTZ (_gdk_root->impl);
-
- g_list_free (root_impl->sorted_children);
- root_impl->sorted_children = NULL;
-}
-
-static void
-gdk_surface_quartz_raise (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- if (SURFACE_IS_TOPLEVEL (window))
- {
- GdkSurfaceImplQuartz *impl;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
- [impl->toplevel orderFront:impl->toplevel];
-
- clear_toplevel_order ();
- }
- else
- {
- GdkSurface *parent = window->parent;
-
- if (parent)
- {
- GdkSurfaceImplQuartz *impl;
-
- impl = (GdkSurfaceImplQuartz *)parent->impl;
-
- impl->sorted_children = g_list_remove (impl->sorted_children, window);
- impl->sorted_children = g_list_prepend (impl->sorted_children, window);
- }
- }
-}
-
-static void
-gdk_surface_quartz_lower (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- if (SURFACE_IS_TOPLEVEL (window))
- {
- GdkSurfaceImplQuartz *impl;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
- [impl->toplevel orderBack:impl->toplevel];
-
- clear_toplevel_order ();
- }
- else
- {
- GdkSurface *parent = window->parent;
-
- if (parent)
- {
- GdkSurfaceImplQuartz *impl;
-
- impl = (GdkSurfaceImplQuartz *)parent->impl;
-
- impl->sorted_children = g_list_remove (impl->sorted_children, window);
- impl->sorted_children = g_list_append (impl->sorted_children, window);
- }
- }
-}
-
-static void
-gdk_surface_quartz_get_geometry (GdkSurface *window,
- gint *x,
- gint *y,
- gint *width,
- gint *height)
-{
- GdkSurfaceImplQuartz *impl;
- NSRect ns_rect;
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
- if (window == _gdk_root)
- {
- if (x)
- *x = 0;
- if (y)
- *y = 0;
-
- if (width)
- *width = window->width;
- if (height)
- *height = window->height;
- }
- else if (SURFACE_IS_TOPLEVEL (window))
- {
- ns_rect = [impl->toplevel contentRectForFrameRect:[impl->toplevel frame]];
-
- /* This doesn't work exactly as in X. There doesn't seem to be a
- * way to get the coords relative to the parent window (usually
- * the window frame), but that seems useless except for
- * borderless windows where it's relative to the root window. So
- * we return (0, 0) (should be something like (0, 22)) for
- * windows with borders and the root relative coordinates
- * otherwise.
- */
- if ([impl->toplevel styleMask] == NSBorderlessWindowMask)
- {
- _gdk_quartz_surface_xy_to_gdk_xy (ns_rect.origin.x,
- ns_rect.origin.y + ns_rect.size.height,
- x, y);
- }
- else
- {
- if (x)
- *x = 0;
- if (y)
- *y = 0;
- }
-
- if (width)
- *width = ns_rect.size.width;
- if (height)
- *height = ns_rect.size.height;
- }
- else
- {
- ns_rect = [impl->view frame];
-
- if (x)
- *x = ns_rect.origin.x;
- if (y)
- *y = ns_rect.origin.y;
- if (width)
- *width = ns_rect.size.width;
- if (height)
- *height = ns_rect.size.height;
- }
-}
-
-static void
-gdk_surface_quartz_get_root_coords (GdkSurface *window,
- gint x,
- gint y,
- gint *root_x,
- gint *root_y)
-{
- int tmp_x = 0, tmp_y = 0;
- GdkSurface *toplevel;
- NSRect content_rect;
- GdkSurfaceImplQuartz *impl;
-
- if (GDK_SURFACE_DESTROYED (window))
- {
- if (root_x)
- *root_x = 0;
- if (root_y)
- *root_y = 0;
-
- return;
- }
-
- if (window == _gdk_root)
- {
- if (root_x)
- *root_x = x;
- if (root_y)
- *root_y = y;
-
- return;
- }
-
- toplevel = gdk_surface_get_toplevel (window);
- impl = GDK_SURFACE_IMPL_QUARTZ (toplevel->impl);
-
- content_rect = [impl->toplevel contentRectForFrameRect:[impl->toplevel frame]];
-
- _gdk_quartz_surface_xy_to_gdk_xy (content_rect.origin.x,
- content_rect.origin.y + content_rect.size.height,
- &tmp_x, &tmp_y);
-
- tmp_x += x;
- tmp_y += y;
-
- while (window != toplevel)
- {
- tmp_x += window->x;
- tmp_y += window->y;
-
- window = window->parent;
- }
-
- if (root_x)
- *root_x = tmp_x;
- if (root_y)
- *root_y = tmp_y;
-}
-
-/* Returns coordinates relative to the passed in window. */
-static GdkSurface *
-gdk_surface_quartz_get_device_state_helper (GdkSurface *window,
- GdkDevice *device,
- gdouble *x,
- gdouble *y,
- GdkModifierType *mask)
-{
- NSPoint point;
- gint x_tmp, y_tmp;
- GdkSurface *toplevel;
- GdkSurface *found_window;
-
- g_return_val_if_fail (window == NULL || GDK_IS_SURFACE (window), NULL);
-
- if (GDK_SURFACE_DESTROYED (window))
- {
- *x = 0;
- *y = 0;
- *mask = 0;
- return NULL;
- }
-
- toplevel = gdk_surface_get_toplevel (window);
-
- *mask = _gdk_quartz_events_get_current_keyboard_modifiers () |
- _gdk_quartz_events_get_current_mouse_modifiers ();
-
- /* Get the y coordinate, needs to be flipped. */
- if (window == _gdk_root)
- {
- point = [NSEvent mouseLocation];
- _gdk_quartz_surface_nspoint_to_gdk_xy (point, &x_tmp, &y_tmp);
- }
- else
- {
- GdkSurfaceImplQuartz *impl;
- NSWindow *nswindow;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (toplevel->impl);
- nswindow = impl->toplevel;
-
- point = [nswindow mouseLocationOutsideOfEventStream];
-
- x_tmp = point.x;
- y_tmp = toplevel->height - point.y;
-
- window = (GdkSurface *)toplevel;
- }
-
- found_window = _gdk_quartz_surface_find_child (window, x_tmp, y_tmp,
- FALSE);
-
- /* We never return the root window. */
- if (found_window == _gdk_root)
- found_window = NULL;
-
- *x = x_tmp;
- *y = y_tmp;
-
- return found_window;
-}
-
-static gboolean
-gdk_surface_quartz_get_device_state (GdkSurface *window,
- GdkDevice *device,
- gdouble *x,
- gdouble *y,
- GdkModifierType *mask)
-{
- return gdk_surface_quartz_get_device_state_helper (window,
- device,
- x, y, mask) != NULL;
-}
-
-static void
-gdk_quartz_surface_set_geometry_hints (GdkSurface *window,
- const GdkGeometry *geometry,
- GdkSurfaceHints geom_mask)
-{
- GdkSurfaceImplQuartz *impl;
-
- g_return_if_fail (geometry != NULL);
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !SURFACE_IS_TOPLEVEL (window))
- return;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
- if (!impl->toplevel)
- return;
-
- if (geom_mask & GDK_HINT_POS)
- {
- /* FIXME: Implement */
- }
-
- if (geom_mask & GDK_HINT_USER_POS)
- {
- /* FIXME: Implement */
- }
-
- if (geom_mask & GDK_HINT_USER_SIZE)
- {
- /* FIXME: Implement */
- }
-
- if (geom_mask & GDK_HINT_MIN_SIZE)
- {
- NSSize size;
-
- size.width = geometry->min_width;
- size.height = geometry->min_height;
-
- [impl->toplevel setContentMinSize:size];
- }
-
- if (geom_mask & GDK_HINT_MAX_SIZE)
- {
- NSSize size;
-
- size.width = geometry->max_width;
- size.height = geometry->max_height;
-
- [impl->toplevel setContentMaxSize:size];
- }
-
- if (geom_mask & GDK_HINT_BASE_SIZE)
- {
- /* FIXME: Implement */
- }
-
- if (geom_mask & GDK_HINT_RESIZE_INC)
- {
- NSSize size;
-
- size.width = geometry->width_inc;
- size.height = geometry->height_inc;
-
- [impl->toplevel setContentResizeIncrements:size];
- }
-
- if (geom_mask & GDK_HINT_ASPECT)
- {
- NSSize size;
-
- if (geometry->min_aspect != geometry->max_aspect)
- {
- g_warning ("Only equal minimum and maximum aspect ratios are supported on Mac OS. Using minimum aspect ratio...");
- }
-
- size.width = geometry->min_aspect;
- size.height = 1.0;
-
- [impl->toplevel setContentAspectRatio:size];
- }
-
- if (geom_mask & GDK_HINT_WIN_GRAVITY)
- {
- /* FIXME: Implement */
- }
-}
-
-static void
-gdk_quartz_surface_set_title (GdkSurface *window,
- const gchar *title)
-{
- GdkSurfaceImplQuartz *impl;
-
- g_return_if_fail (title != NULL);
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !SURFACE_IS_TOPLEVEL (window))
- return;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (impl->toplevel)
- {
- GDK_QUARTZ_ALLOC_POOL;
- [impl->toplevel setTitle:[NSString stringWithUTF8String:title]];
- GDK_QUARTZ_RELEASE_POOL;
- }
-}
-
-static void
-gdk_quartz_surface_set_startup_id (GdkSurface *window,
- const gchar *startup_id)
-{
- /* FIXME: Implement? */
-}
-
-static void
-gdk_quartz_surface_set_transient_for (GdkSurface *window,
- GdkSurface *parent)
-{
- GdkSurfaceImplQuartz *surface_impl;
- GdkSurfaceImplQuartz *parent_impl;
-
- if (GDK_SURFACE_DESTROYED (window) || GDK_SURFACE_DESTROYED (parent) ||
- !SURFACE_IS_TOPLEVEL (window))
- return;
-
- surface_impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
- if (!surface_impl->toplevel)
- return;
-
- GDK_QUARTZ_ALLOC_POOL;
-
- if (surface_impl->transient_for)
- {
- _gdk_quartz_surface_detach_from_parent (window);
-
- g_object_unref (surface_impl->transient_for);
- surface_impl->transient_for = NULL;
- }
-
- parent_impl = GDK_SURFACE_IMPL_QUARTZ (parent->impl);
- if (parent_impl->toplevel)
- {
- /* We save the parent because it needs to be unset/reset when
- * hiding and showing the window.
- */
-
- /* We don't set transients for tooltips, they are already
- * handled by the window level being the top one. If we do, then
- * the parent window will be brought to the top just because the
- * tooltip is, which is not what we want.
- */
- if (gdk_surface_get_type_hint (window) != GDK_SURFACE_TYPE_HINT_TOOLTIP)
- {
- surface_impl->transient_for = g_object_ref (parent);
-
- /* We only add the window if it is shown, otherwise it will
- * be shown unconditionally here. If it is not shown, the
- * window will be added in show() instead.
- */
- if (!(window->state & GDK_SURFACE_STATE_WITHDRAWN))
- _gdk_quartz_surface_attach_to_parent (window);
- }
- }
-
- GDK_QUARTZ_RELEASE_POOL;
-}
-
-static void
-gdk_surface_quartz_input_shape_combine_region (GdkSurface *window,
- const cairo_region_t *shape_region,
- gint offset_x,
- gint offset_y)
-{
- /* FIXME: Implement */
-}
-
-static void
-gdk_quartz_surface_set_accept_focus (GdkSurface *window,
- gboolean accept_focus)
-{
- window->accept_focus = accept_focus != FALSE;
-}
-
-static void
-gdk_quartz_surface_set_focus_on_map (GdkSurface *window,
- gboolean focus_on_map)
-{
- window->focus_on_map = focus_on_map != FALSE;
-}
-
-static void
-gdk_quartz_surface_focus (GdkSurface *window,
- guint32 timestamp)
-{
- GdkSurfaceImplQuartz *impl;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !SURFACE_IS_TOPLEVEL (window))
- return;
-
- if (window->accept_focus && window->surface_type != GDK_SURFACE_TEMP)
- {
- GDK_QUARTZ_ALLOC_POOL;
- [impl->toplevel makeKeyAndOrderFront:impl->toplevel];
- clear_toplevel_order ();
- GDK_QUARTZ_RELEASE_POOL;
- }
-}
-
-static gint
-surface_type_hint_to_level (GdkSurfaceTypeHint hint)
-{
- /* the order in this switch statement corresponds to the actual
- * stacking order: the first group is top, the last group is bottom
- */
- switch (hint)
- {
- case GDK_SURFACE_TYPE_HINT_POPUP_MENU:
- case GDK_SURFACE_TYPE_HINT_COMBO:
- case GDK_SURFACE_TYPE_HINT_DND:
- case GDK_SURFACE_TYPE_HINT_TOOLTIP:
- return NSPopUpMenuWindowLevel;
-
- case GDK_SURFACE_TYPE_HINT_NOTIFICATION:
- case GDK_SURFACE_TYPE_HINT_SPLASHSCREEN:
- return NSStatusWindowLevel;
-
- case GDK_SURFACE_TYPE_HINT_MENU: /* Torn-off menu */
- case GDK_SURFACE_TYPE_HINT_DROPDOWN_MENU: /* Menu from menubar */
- return NSTornOffMenuWindowLevel;
-
- case GDK_SURFACE_TYPE_HINT_DOCK:
- return NSFloatingWindowLevel; /* NSDockWindowLevel is deprecated, and not replaced */
-
- case GDK_SURFACE_TYPE_HINT_UTILITY:
- case GDK_SURFACE_TYPE_HINT_DIALOG: /* Dialog window */
- case GDK_SURFACE_TYPE_HINT_NORMAL: /* Normal toplevel window */
- case GDK_SURFACE_TYPE_HINT_TOOLBAR: /* Window used to implement toolbars */
- return NSNormalWindowLevel;
-
- case GDK_SURFACE_TYPE_HINT_DESKTOP:
- return kCGDesktopWindowLevelKey; /* doesn't map to any real Cocoa model */
-
- default:
- break;
- }
-
- return NSNormalWindowLevel;
-}
-
-static gboolean
-surface_type_hint_to_shadow (GdkSurfaceTypeHint hint)
-{
- switch (hint)
- {
- case GDK_SURFACE_TYPE_HINT_NORMAL: /* Normal toplevel window */
- case GDK_SURFACE_TYPE_HINT_DIALOG: /* Dialog window */
- case GDK_SURFACE_TYPE_HINT_DOCK:
- case GDK_SURFACE_TYPE_HINT_UTILITY:
- case GDK_SURFACE_TYPE_HINT_MENU: /* Torn-off menu */
- case GDK_SURFACE_TYPE_HINT_DROPDOWN_MENU: /* Menu from menubar */
- case GDK_SURFACE_TYPE_HINT_SPLASHSCREEN:
- case GDK_SURFACE_TYPE_HINT_POPUP_MENU:
- case GDK_SURFACE_TYPE_HINT_COMBO:
- case GDK_SURFACE_TYPE_HINT_NOTIFICATION:
- case GDK_SURFACE_TYPE_HINT_TOOLTIP:
- return TRUE;
-
- case GDK_SURFACE_TYPE_HINT_TOOLBAR: /* Window used to implement toolbars */
- case GDK_SURFACE_TYPE_HINT_DESKTOP: /* N/A */
- case GDK_SURFACE_TYPE_HINT_DND:
- break;
-
- default:
- break;
- }
-
- return FALSE;
-}
-
-static gboolean
-surface_type_hint_to_hides_on_deactivate (GdkSurfaceTypeHint hint)
-{
- switch (hint)
- {
- case GDK_SURFACE_TYPE_HINT_UTILITY:
- case GDK_SURFACE_TYPE_HINT_MENU: /* Torn-off menu */
- case GDK_SURFACE_TYPE_HINT_SPLASHSCREEN:
- case GDK_SURFACE_TYPE_HINT_NOTIFICATION:
- case GDK_SURFACE_TYPE_HINT_TOOLTIP:
- return TRUE;
-
- default:
- break;
- }
-
- return FALSE;
-}
-
-static void
-_gdk_quartz_surface_update_has_shadow (GdkSurfaceImplQuartz *impl)
-{
- gboolean has_shadow;
-
- /* In case there is any shadow set we have to turn off the
- * NSWindow setHasShadow as the system drawn ones wont match our
- * window boundary anymore */
- has_shadow = (surface_type_hint_to_shadow (impl->type_hint) && !impl->shadow_max);
-
- [impl->toplevel setHasShadow: has_shadow];
-}
-
-static void
-gdk_quartz_surface_set_type_hint (GdkSurface *window,
- GdkSurfaceTypeHint hint)
-{
- GdkSurfaceImplQuartz *impl;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !SURFACE_IS_TOPLEVEL (window))
- return;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- impl->type_hint = hint;
-
- /* Match the documentation, only do something if we're not mapped yet. */
- if (GDK_SURFACE_IS_MAPPED (window))
- return;
-
- _gdk_quartz_surface_update_has_shadow (impl);
- [impl->toplevel setLevel: surface_type_hint_to_level (hint)];
- [impl->toplevel setHidesOnDeactivate: surface_type_hint_to_hides_on_deactivate (hint)];
-}
-
-static GdkSurfaceTypeHint
-gdk_quartz_surface_get_type_hint (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !SURFACE_IS_TOPLEVEL (window))
- return GDK_SURFACE_TYPE_HINT_NORMAL;
-
- return GDK_SURFACE_IMPL_QUARTZ (window->impl)->type_hint;
-}
-
-static void
-gdk_quartz_surface_set_modal_hint (GdkSurface *window,
- gboolean modal)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !SURFACE_IS_TOPLEVEL (window))
- return;
-
- /* FIXME: Implement */
-}
-
-static void
-gdk_quartz_surface_begin_resize_drag (GdkSurface *window,
- GdkSurfaceEdge edge,
- GdkDevice *device,
- gint button,
- gint root_x,
- gint root_y,
- guint32 timestamp)
-{
- GdkSurfaceImplQuartz *impl;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window))
- return;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (!impl->toplevel)
- {
- g_warning ("Can't call gdk_surface_begin_resize_drag on non-toplevel window");
- return;
- }
-
- [(GdkQuartzNSWindow *)impl->toplevel beginManualResize:edge];
-}
-
-static void
-gdk_quartz_surface_begin_move_drag (GdkSurface *window,
- GdkDevice *device,
- gint button,
- gint root_x,
- gint root_y,
- guint32 timestamp)
-{
- GdkSurfaceImplQuartz *impl;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !SURFACE_IS_TOPLEVEL (window))
- return;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (!impl->toplevel)
- {
- g_warning ("Can't call gdk_surface_begin_move_drag on non-toplevel window");
- return;
- }
-
- [(GdkQuartzNSWindow *)impl->toplevel beginManualMove];
-}
-
-static void
-gdk_quartz_surface_set_icon_list (GdkSurface *window,
- GList *surfaces)
-{
- /* FIXME: Implement */
-}
-
-static void
-gdk_quartz_surface_get_frame_extents (GdkSurface *window,
- GdkRectangle *rect)
-{
- GdkSurface *toplevel;
- GdkSurfaceImplQuartz *impl;
- NSRect ns_rect;
-
- g_return_if_fail (rect != NULL);
-
-
- rect->x = 0;
- rect->y = 0;
- rect->width = 1;
- rect->height = 1;
-
- toplevel = gdk_surface_get_toplevel (window);
- impl = GDK_SURFACE_IMPL_QUARTZ (toplevel->impl);
-
- ns_rect = [impl->toplevel frame];
-
- _gdk_quartz_surface_xy_to_gdk_xy (ns_rect.origin.x,
- ns_rect.origin.y + ns_rect.size.height,
- &rect->x, &rect->y);
-
- rect->width = ns_rect.size.width;
- rect->height = ns_rect.size.height;
-}
-
-/* Fake protocol to make gcc think that it's OK to call setStyleMask
- even if it isn't. We check to make sure before actually calling
- it. */
-
-@protocol CanSetStyleMask
-- (void)setStyleMask:(int)mask;
-@end
-
-static void
-gdk_quartz_surface_set_decorations (GdkSurface *window,
- GdkWMDecoration decorations)
-{
- GdkSurfaceImplQuartz *impl;
- NSUInteger old_mask, new_mask;
- NSView *old_view;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !SURFACE_IS_TOPLEVEL (window))
- return;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (decorations == 0 || GDK_SURFACE_TYPE (window) == GDK_SURFACE_TEMP ||
- impl->type_hint == GDK_SURFACE_TYPE_HINT_SPLASHSCREEN )
- {
- new_mask = NSBorderlessWindowMask;
- }
- else
- {
- /* FIXME: Honor other GDK_DECOR_* flags. */
- new_mask = (NSTitledWindowMask | NSClosableWindowMask |
- NSMiniaturizableWindowMask | NSResizableWindowMask);
- }
-
- GDK_QUARTZ_ALLOC_POOL;
-
- old_mask = [impl->toplevel styleMask];
-
- if (old_mask != new_mask)
- {
- NSRect rect;
-
- old_view = [[impl->toplevel contentView] retain];
-
- rect = [impl->toplevel frame];
-
- /* Properly update the size of the window when the titlebar is
- * added or removed.
- */
- if (old_mask == NSBorderlessWindowMask &&
- new_mask != NSBorderlessWindowMask)
- {
- rect = [NSWindow frameRectForContentRect:rect styleMask:new_mask];
-
- }
- else if (old_mask != NSBorderlessWindowMask &&
- new_mask == NSBorderlessWindowMask)
- {
- rect = [NSWindow contentRectForFrameRect:rect styleMask:old_mask];
- }
-
- /* Note, before OS 10.6 there doesn't seem to be a way to change this
- * without recreating the toplevel. From 10.6 onward, a simple call to
- * setStyleMask takes care of most of this, except for ensuring that the
- * title is set.
- */
- if ([impl->toplevel respondsToSelector:@selector(setStyleMask:)])
- {
- NSString *title = [impl->toplevel title];
-
- [(id<CanSetStyleMask>)impl->toplevel setStyleMask:new_mask];
-
- /* It appears that unsetting and then resetting NSTitledWindowMask
- * does not reset the title in the title bar as might be expected.
- *
- * In theory we only need to set this if new_mask includes
- * NSTitledWindowMask. This behaved extremely oddly when
- * conditionalized upon that and since it has no side effects (i.e.
- * if NSTitledWindowMask is not requested, the title will not be
- * displayed) just do it unconditionally. We also must null check
- * 'title' before setting it to avoid crashing.
- */
- if (title)
- [impl->toplevel setTitle:title];
- }
- else
- {
- NSString *title = [impl->toplevel title];
- NSColor *bg = [impl->toplevel backgroundColor];
- NSScreen *screen = [impl->toplevel screen];
-
- /* Make sure the old window is closed, recall that releasedWhenClosed
- * is set on GdkQuartzSurfaces.
- */
- [impl->toplevel close];
-
- impl->toplevel = [[GdkQuartzNSWindow alloc] initWithContentRect:rect
- styleMask:new_mask
- backing:NSBackingStoreBuffered
- defer:NO
- screen:screen];
- _gdk_quartz_surface_update_has_shadow (impl);
-
- [impl->toplevel setLevel: surface_type_hint_to_level (impl->type_hint)];
- if (title)
- [impl->toplevel setTitle:title];
- [impl->toplevel setBackgroundColor:bg];
- [impl->toplevel setHidesOnDeactivate: surface_type_hint_to_hides_on_deactivate (impl->type_hint)];
- [impl->toplevel setContentView:old_view];
- }
-
- if (new_mask == NSBorderlessWindowMask)
- {
- [impl->toplevel setContentSize:rect.size];
- [impl->toplevel setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
- }
- else
- [impl->toplevel setFrame:rect display:YES];
-
- /* Invalidate the window shadow for non-opaque views that have shadow
- * enabled, to get the shadow shape updated.
- */
- if (![old_view isOpaque] && [impl->toplevel hasShadow])
- [(GdkQuartzView*)old_view setNeedsInvalidateShadow:YES];
-
- [old_view release];
- }
-
- GDK_QUARTZ_RELEASE_POOL;
-}
-
-static gboolean
-gdk_quartz_surface_get_decorations (GdkSurface *window,
- GdkWMDecoration *decorations)
-{
- GdkSurfaceImplQuartz *impl;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !SURFACE_IS_TOPLEVEL (window))
- return FALSE;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (decorations)
- {
- /* Borderless is 0, so we can't check it as a bit being set. */
- if ([impl->toplevel styleMask] == NSBorderlessWindowMask)
- {
- *decorations = 0;
- }
- else
- {
- /* FIXME: Honor the other GDK_DECOR_* flags. */
- *decorations = GDK_DECOR_ALL;
- }
- }
-
- return TRUE;
-}
-
-static void
-gdk_quartz_surface_stick (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !SURFACE_IS_TOPLEVEL (window))
- return;
-}
-
-static void
-gdk_quartz_surface_unstick (GdkSurface *window)
-{
- if (GDK_SURFACE_DESTROYED (window) ||
- !SURFACE_IS_TOPLEVEL (window))
- return;
-}
-
-static void
-gdk_quartz_surface_maximize (GdkSurface *window)
-{
- GdkSurfaceImplQuartz *impl;
- gboolean maximized;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !SURFACE_IS_TOPLEVEL (window))
- return;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
- maximized = gdk_surface_get_state (window) & GDK_SURFACE_STATE_MAXIMIZED;
-
- if (GDK_SURFACE_IS_MAPPED (window))
- {
- GDK_QUARTZ_ALLOC_POOL;
-
- if (impl->toplevel && !maximized)
- [impl->toplevel zoom:nil];
-
- GDK_QUARTZ_RELEASE_POOL;
- }
-}
-
-static void
-gdk_quartz_surface_unmaximize (GdkSurface *window)
-{
- GdkSurfaceImplQuartz *impl;
- gboolean maximized;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !SURFACE_IS_TOPLEVEL (window))
- return;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
- maximized = gdk_surface_get_state (window) & GDK_SURFACE_STATE_MAXIMIZED;
-
- if (GDK_SURFACE_IS_MAPPED (window))
- {
- GDK_QUARTZ_ALLOC_POOL;
-
- if (impl->toplevel && maximized)
- [impl->toplevel zoom:nil];
-
- GDK_QUARTZ_RELEASE_POOL;
- }
-}
-
-static void
-gdk_quartz_surface_minimize (GdkSurface *window)
-{
- GdkSurfaceImplQuartz *impl;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !SURFACE_IS_TOPLEVEL (window))
- return;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (GDK_SURFACE_IS_MAPPED (window))
- {
- GDK_QUARTZ_ALLOC_POOL;
-
- if (impl->toplevel)
- [impl->toplevel miniaturize:nil];
-
- GDK_QUARTZ_RELEASE_POOL;
- }
- else
- {
- gdk_synthesize_surface_state (window, 0, GDK_SURFACE_STATE_MINIMIZED);
- }
-}
-
-static void
-gdk_quartz_surface_unminimize (GdkSurface *window)
-{
- GdkSurfaceImplQuartz *impl;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !SURFACE_IS_TOPLEVEL (window))
- return;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (GDK_SURFACE_IS_MAPPED (window))
- {
- GDK_QUARTZ_ALLOC_POOL;
-
- if (impl->toplevel)
- [impl->toplevel deminiaturize:nil];
-
- GDK_QUARTZ_RELEASE_POOL;
- }
- else
- {
- gdk_synthesize_surface_state (window, GDK_SURFACE_STATE_MINIMIZED, 0);
- }
-}
-
-#ifdef AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER
-
-static gboolean
-window_is_fullscreen (GdkSurface *window)
-{
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- return ([impl->toplevel styleMask] & NSFullScreenWindowMask) != 0;
-}
-
-static void
-gdk_quartz_surface_fullscreen (GdkSurface *window)
-{
- GdkSurfaceImplQuartz *impl;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !SURFACE_IS_TOPLEVEL (window))
- return;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (!window_is_fullscreen (window))
- [impl->toplevel toggleFullScreen:nil];
-}
-
-static void
-gdk_quartz_surface_unfullscreen (GdkSurface *window)
-{
- GdkSurfaceImplQuartz *impl;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !SURFACE_IS_TOPLEVEL (window))
- return;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (window_is_fullscreen (window))
- [impl->toplevel toggleFullScreen:nil];
-}
-
-void
-_gdk_quartz_surface_update_fullscreen_state (GdkSurface *window)
-{
- gboolean is_fullscreen;
- gboolean was_fullscreen;
-
- is_fullscreen = window_is_fullscreen (window);
- was_fullscreen = (gdk_surface_get_state (window) & GDK_SURFACE_STATE_FULLSCREEN) != 0;
-
- if (is_fullscreen != was_fullscreen)
- {
- if (is_fullscreen)
- gdk_synthesize_surface_state (window, 0, GDK_SURFACE_STATE_FULLSCREEN);
- else
- gdk_synthesize_surface_state (window, GDK_SURFACE_STATE_FULLSCREEN, 0);
- }
-}
-
-#else
-
-static FullscreenSavedGeometry *
-get_fullscreen_geometry (GdkSurface *window)
-{
- return g_object_get_data (G_OBJECT (window), FULLSCREEN_DATA);
-}
-
-static void
-gdk_quartz_surface_fullscreen (GdkSurface *window)
-{
- FullscreenSavedGeometry *geometry;
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
- NSRect frame;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !SURFACE_IS_TOPLEVEL (window))
- return;
-
- geometry = get_fullscreen_geometry (window);
- if (!geometry)
- {
- geometry = g_new (FullscreenSavedGeometry, 1);
-
- geometry->x = window->x;
- geometry->y = window->y;
- geometry->width = window->width;
- geometry->height = window->height;
-
- if (!gdk_quartz_surface_get_decorations (window, &geometry->decor))
- geometry->decor = GDK_DECOR_ALL;
-
- g_object_set_data_full (G_OBJECT (window),
- FULLSCREEN_DATA, geometry,
- g_free);
-
- gdk_quartz_surface_set_decorations (window, 0);
-
- frame = [[impl->toplevel screen] frame];
- move_resize_window_internal (window,
- 0, 0,
- frame.size.width, frame.size.height);
- [impl->toplevel setContentSize:frame.size];
- [impl->toplevel makeKeyAndOrderFront:impl->toplevel];
-
- clear_toplevel_order ();
- }
-
- SetSystemUIMode (kUIModeAllHidden, kUIOptionAutoShowMenuBar);
-
- gdk_synthesize_surface_state (window, 0, GDK_SURFACE_STATE_FULLSCREEN);
-}
-
-static void
-gdk_quartz_surface_unfullscreen (GdkSurface *window)
-{
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
- FullscreenSavedGeometry *geometry;
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !SURFACE_IS_TOPLEVEL (window))
- return;
-
- geometry = get_fullscreen_geometry (window);
- if (geometry)
- {
- SetSystemUIMode (kUIModeNormal, 0);
-
- move_resize_window_internal (window,
- geometry->x,
- geometry->y,
- geometry->width,
- geometry->height);
-
- gdk_quartz_surface_set_decorations (window, geometry->decor);
-
- g_object_set_data (G_OBJECT (window), FULLSCREEN_DATA, NULL);
-
- [impl->toplevel makeKeyAndOrderFront:impl->toplevel];
- clear_toplevel_order ();
-
- gdk_synthesize_surface_state (window, GDK_SURFACE_STATE_FULLSCREEN, 0);
- }
-}
-
-#endif
-
-static void
-gdk_quartz_surface_set_keep_above (GdkSurface *window,
- gboolean setting)
-{
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
- gint level;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !SURFACE_IS_TOPLEVEL (window))
- return;
-
- level = surface_type_hint_to_level (gdk_surface_get_type_hint (window));
-
- /* Adjust normal window level by one if necessary. */
- [impl->toplevel setLevel: level + (setting ? 1 : 0)];
-}
-
-static void
-gdk_quartz_surface_set_keep_below (GdkSurface *window,
- gboolean setting)
-{
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
- gint level;
-
- g_return_if_fail (GDK_IS_SURFACE (window));
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !SURFACE_IS_TOPLEVEL (window))
- return;
-
- level = surface_type_hint_to_level (gdk_surface_get_type_hint (window));
-
- /* Adjust normal window level by one if necessary. */
- [impl->toplevel setLevel: level - (setting ? 1 : 0)];
-}
-
-static void
-gdk_quartz_surface_destroy_notify (GdkSurface *window)
-{
- check_grab_destroy (window);
-}
-
-static void
-gdk_quartz_surface_set_opacity (GdkSurface *window,
- gdouble opacity)
-{
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- g_return_if_fail (GDK_IS_SURFACE (window));
- g_return_if_fail (SURFACE_IS_TOPLEVEL (window));
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !SURFACE_IS_TOPLEVEL (window))
- return;
-
- if (opacity < 0)
- opacity = 0;
- else if (opacity > 1)
- opacity = 1;
-
- [impl->toplevel setAlphaValue: opacity];
-}
-
-static void
-gdk_quartz_surface_set_shadow_width (GdkSurface *window,
- gint left,
- gint right,
- gint top,
- gint bottom)
-{
- GdkSurfaceImplQuartz *impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- g_return_if_fail (GDK_IS_SURFACE (window));
- g_return_if_fail (SURFACE_IS_TOPLEVEL (window));
-
- if (GDK_SURFACE_DESTROYED (window) ||
- !SURFACE_IS_TOPLEVEL (window))
- return;
-
- impl->shadow_top = top;
- impl->shadow_max = MAX (MAX (left, right), MAX (top, bottom));
- _gdk_quartz_surface_update_has_shadow (impl);
-}
-
-/* Protocol to build cleanly for OSX < 10.7 */
-@protocol ScaleFactor
-- (CGFloat) backingScaleFactor;
-@end
-
-static gint
-gdk_quartz_surface_get_scale_factor (GdkSurface *window)
-{
- GdkSurfaceImplQuartz *impl;
-
- if (GDK_SURFACE_DESTROYED (window))
- return 1;
-
- impl = GDK_SURFACE_IMPL_QUARTZ (window->impl);
-
- if (impl->toplevel != NULL && gdk_quartz_osx_version() >= GDK_OSX_LION)
- return [(id <ScaleFactor>) impl->toplevel backingScaleFactor];
-
- return 1;
-}
-
-static void
-gdk_surface_impl_quartz_class_init (GdkSurfaceImplQuartzClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GdkSurfaceImplClass *impl_class = GDK_SURFACE_IMPL_CLASS (klass);
- GdkSurfaceImplQuartzClass *impl_quartz_class = GDK_SURFACE_IMPL_QUARTZ_CLASS (klass);
-
- parent_class = g_type_class_peek_parent (klass);
-
- object_class->finalize = gdk_surface_impl_quartz_finalize;
-
- impl_class->ref_cairo_surface = gdk_quartz_ref_cairo_surface;
- impl_class->show = gdk_surface_quartz_show;
- impl_class->hide = gdk_surface_quartz_hide;
- impl_class->withdraw = gdk_surface_quartz_withdraw;
- impl_class->raise = gdk_surface_quartz_raise;
- impl_class->lower = gdk_surface_quartz_lower;
- impl_class->toplevel_resize = gdk_surface_quartz_toplevel_resize;
- impl_class->present_popup = gdk_quartz_surface_present_popup;
- impl_class->get_geometry = gdk_surface_quartz_get_geometry;
- impl_class->get_root_coords = gdk_surface_quartz_get_root_coords;
- impl_class->get_device_state = gdk_surface_quartz_get_device_state;
- impl_class->input_shape_combine_region = gdk_surface_quartz_input_shape_combine_region;
- impl_class->destroy = gdk_quartz_surface_destroy;
- impl_class->begin_paint = gdk_surface_impl_quartz_begin_paint;
- impl_class->get_scale_factor = gdk_quartz_surface_get_scale_factor;
-
- impl_class->focus = gdk_quartz_surface_focus;
- impl_class->set_type_hint = gdk_quartz_surface_set_type_hint;
- impl_class->get_type_hint = gdk_quartz_surface_get_type_hint;
- impl_class->set_modal_hint = gdk_quartz_surface_set_modal_hint;
- impl_class->set_geometry_hints = gdk_quartz_surface_set_geometry_hints;
- impl_class->set_title = gdk_quartz_surface_set_title;
- impl_class->set_startup_id = gdk_quartz_surface_set_startup_id;
- impl_class->set_transient_for = gdk_quartz_surface_set_transient_for;
- impl_class->get_frame_extents = gdk_quartz_surface_get_frame_extents;
- impl_class->set_accept_focus = gdk_quartz_surface_set_accept_focus;
- impl_class->set_focus_on_map = gdk_quartz_surface_set_focus_on_map;
- impl_class->set_icon_list = gdk_quartz_surface_set_icon_list;
- impl_class->minimize = gdk_quartz_surface_minimize;
- impl_class->unminimize = gdk_quartz_surface_unminimize;
- impl_class->stick = gdk_quartz_surface_stick;
- impl_class->unstick = gdk_quartz_surface_unstick;
- impl_class->maximize = gdk_quartz_surface_maximize;
- impl_class->unmaximize = gdk_quartz_surface_unmaximize;
- impl_class->fullscreen = gdk_quartz_surface_fullscreen;
- impl_class->unfullscreen = gdk_quartz_surface_unfullscreen;
- impl_class->set_keep_above = gdk_quartz_surface_set_keep_above;
- impl_class->set_keep_below = gdk_quartz_surface_set_keep_below;
- impl_class->begin_resize_drag = gdk_quartz_surface_begin_resize_drag;
- impl_class->begin_move_drag = gdk_quartz_surface_begin_move_drag;
- impl_class->set_opacity = gdk_quartz_surface_set_opacity;
- impl_class->set_shadow_width = gdk_quartz_surface_set_shadow_width;
- impl_class->destroy_notify = gdk_quartz_surface_destroy_notify;
- impl_class->drag_begin = _gdk_quartz_surface_drag_begin;
- impl_class->process_updates_recurse = _gdk_quartz_surface_process_updates_recurse;
-
- impl_class->create_gl_context = gdk_quartz_surface_create_gl_context;
-
- impl_quartz_class->get_context = gdk_surface_impl_quartz_get_context;
- impl_quartz_class->release_context = gdk_surface_impl_quartz_release_context;
-}
-
-GType
-_gdk_surface_impl_quartz_get_type (void)
-{
- static GType object_type = 0;
-
- if (!object_type)
- {
- const GTypeInfo object_info =
- {
- sizeof (GdkSurfaceImplQuartzClass),
- (GBaseInitFunc) NULL,
- (GBaseFinalizeFunc) NULL,
- (GClassInitFunc) gdk_surface_impl_quartz_class_init,
- NULL, /* class_finalize */
- NULL, /* class_data */
- sizeof (GdkSurfaceImplQuartz),
- 0, /* n_preallocs */
- (GInstanceInitFunc) gdk_surface_impl_quartz_init,
- };
-
- object_type = g_type_register_static (GDK_TYPE_SURFACE_IMPL,
- "GdkSurfaceImplQuartz",
- &object_info, 0);
- }
-
- return object_type;
-}
-
-CGContextRef
-gdk_quartz_surface_get_context (GdkSurfaceImplQuartz *window,
- gboolean antialias)
-{
- if (!GDK_SURFACE_IMPL_QUARTZ_GET_CLASS (window)->get_context)
- {
- g_warning ("%s doesn't implement GdkSurfaceImplQuartzClass::get_context()",
- G_OBJECT_TYPE_NAME (window));
- return NULL;
- }
-
- return GDK_SURFACE_IMPL_QUARTZ_GET_CLASS (window)->get_context (window, antialias);
-}
-
-void
-gdk_quartz_surface_release_context (GdkSurfaceImplQuartz *window,
- CGContextRef cg_context)
-{
- if (!GDK_SURFACE_IMPL_QUARTZ_GET_CLASS (window)->release_context)
- {
- g_warning ("%s doesn't implement GdkSurfaceImplQuartzClass::release_context()",
- G_OBJECT_TYPE_NAME (window));
- return;
- }
-
- GDK_SURFACE_IMPL_QUARTZ_GET_CLASS (window)->release_context (window, cg_context);
-}
-
-
-
-static CGContextRef
-gdk_root_surface_impl_quartz_get_context (GdkSurfaceImplQuartz *window,
- gboolean antialias)
-{
- CGColorSpaceRef colorspace;
- CGContextRef cg_context;
- GdkSurfaceImplQuartz *surface_impl = GDK_SURFACE_IMPL_QUARTZ (window);
-
- if (GDK_SURFACE_DESTROYED (surface_impl->wrapper))
- return NULL;
-
- /* We do not have the notion of a root window on OS X. We fake this
- * by creating a 1x1 bitmap and return a context to that.
- */
- colorspace = CGColorSpaceCreateWithName (kCGColorSpaceGenericRGB);
- cg_context = CGBitmapContextCreate (NULL,
- 1, 1, 8, 4, colorspace,
- kCGImageAlphaPremultipliedLast);
- CGColorSpaceRelease (colorspace);
-
- return cg_context;
-}
-
-static void
-gdk_root_surface_impl_quartz_release_context (GdkSurfaceImplQuartz *window,
- CGContextRef cg_context)
-{
- CGContextRelease (cg_context);
-}
-
-static void
-gdk_root_surface_impl_quartz_class_init (GdkRootWindowImplQuartzClass *klass)
-{
- GdkSurfaceImplQuartzClass *window_quartz_class = GDK_SURFACE_IMPL_QUARTZ_CLASS (klass);
-
- root_window_parent_class = g_type_class_peek_parent (klass);
-
- window_quartz_class->get_context = gdk_root_surface_impl_quartz_get_context;
- window_quartz_class->release_context = gdk_root_surface_impl_quartz_release_context;
-}
-
-static void
-gdk_root_surface_impl_quartz_init (GdkRootWindowImplQuartz *impl)
-{
-}
-
-GType
-_gdk_root_surface_impl_quartz_get_type (void)
-{
- static GType object_type = 0;
-
- if (!object_type)
- {
- const GTypeInfo object_info =
- {
- sizeof (GdkRootWindowImplQuartzClass),
- (GBaseInitFunc) NULL,
- (GBaseFinalizeFunc) NULL,
- (GClassInitFunc) gdk_root_surface_impl_quartz_class_init,
- NULL, /* class_finalize */
- NULL, /* class_data */
- sizeof (GdkRootWindowImplQuartz),
- 0, /* n_preallocs */
- (GInstanceInitFunc) gdk_root_surface_impl_quartz_init,
- };
-
- object_type = g_type_register_static (GDK_TYPE_SURFACE_IMPL_QUARTZ,
- "GdkRootWindowQuartz",
- &object_info, 0);
- }
-
- return object_type;
-}
-
-GList *
-get_toplevels (void)
-{
- update_toplevel_order ();
- return GDK_SURFACE_IMPL_QUARTZ (_gdk_root->impl)->sorted_children;
-}
+++ /dev/null
-/* gdkdrawable-quartz.h
- *
- * Copyright (C) 2005 Imendio AB
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __GDK_SURFACE_QUARTZ_H__
-#define __GDK_SURFACE_QUARTZ_H__
-
-#import <gdk/quartz/GdkQuartzView.h>
-#import <gdk/quartz/GdkQuartzNSWindow.h>
-#include "gdk/gdksurfaceimpl.h"
-
-G_BEGIN_DECLS
-
-/* Window implementation for Quartz
- */
-
-typedef struct _GdkSurfaceImplQuartz GdkSurfaceImplQuartz;
-typedef struct _GdkSurfaceImplQuartzClass GdkSurfaceImplQuartzClass;
-
-#define GDK_TYPE_SURFACE_IMPL_QUARTZ (_gdk_surface_impl_quartz_get_type ())
-#define GDK_SURFACE_IMPL_QUARTZ(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_SURFACE_IMPL_QUARTZ, GdkSurfaceImplQuartz))
-#define GDK_SURFACE_IMPL_QUARTZ_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_SURFACE_IMPL_QUARTZ, GdkSurfaceImplQuartzClass))
-#define GDK_IS_SURFACE_IMPL_QUARTZ(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_SURFACE_IMPL_QUARTZ))
-#define GDK_IS_SURFACE_IMPL_QUARTZ_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_SURFACE_IMPL_QUARTZ))
-#define GDK_SURFACE_IMPL_QUARTZ_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_SURFACE_IMPL_QUARTZ, GdkSurfaceImplQuartzClass))
-
-struct _GdkSurfaceImplQuartz
-{
- GdkSurfaceImpl parent_instance;
-
- GdkSurface *wrapper;
-
- NSWindow *toplevel;
- NSTrackingRectTag tracking_rect;
- GdkQuartzView *view;
-
- GdkSurfaceTypeHint type_hint;
-
- gint in_paint_rect_count;
-
- GdkSurface *transient_for;
-
- /* Sorted by z-order */
- GList *sorted_children;
-
- cairo_region_t *needs_display_region;
-
- cairo_surface_t *cairo_surface;
-
- gint shadow_top;
-
- gint shadow_max;
-};
-
-struct _GdkSurfaceImplQuartzClass
-{
- GdkSurfaceImplClass parent_class;
-
- CGContextRef (* get_context) (GdkSurfaceImplQuartz *window,
- gboolean antialias);
- void (* release_context) (GdkSurfaceImplQuartz *window,
- CGContextRef cg_context);
-};
-
-GType _gdk_surface_impl_quartz_get_type (void);
-
-CGContextRef gdk_quartz_surface_get_context (GdkSurfaceImplQuartz *window,
- gboolean antialias);
-void gdk_quartz_surface_release_context (GdkSurfaceImplQuartz *window,
- CGContextRef context);
-
-/* Root window implementation for Quartz
- */
-
-typedef struct _GdkRootWindowImplQuartz GdkRootWindowImplQuartz;
-typedef struct _GdkRootWindowImplQuartzClass GdkRootWindowImplQuartzClass;
-
-#define GDK_TYPE_ROOT_SURFACE_IMPL_QUARTZ (_gdk_root_surface_impl_quartz_get_type ())
-#define GDK_ROOT_SURFACE_IMPL_QUARTZ(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_ROOT_SURFACE_IMPL_QUARTZ, GdkRootWindowImplQuartz))
-#define GDK_ROOT_SURFACE_IMPL_QUARTZ_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_ROOT_SURFACE_IMPL_QUARTZ, GdkRootWindowImplQuartzClass))
-#define GDK_IS_ROOT_SURFACE_IMPL_QUARTZ(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_ROOT_SURFACE_IMPL_QUARTZ))
-#define GDK_IS_ROOT_SURFACE_IMPL_QUARTZ_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_ROOT_SURFACE_IMPL_QUARTZ))
-#define GDK_ROOT_SURFACE_IMPL_QUARTZ_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_ROOT_SURFACE_IMPL_QUARTZ, GdkRootWindowImplQuartzClass))
-
-struct _GdkRootWindowImplQuartz
-{
- GdkSurfaceImplQuartz parent_instance;
-};
-
-struct _GdkRootWindowImplQuartzClass
-{
- GdkSurfaceImplQuartzClass parent_class;
-};
-
-GType _gdk_root_surface_impl_quartz_get_type (void);
-
-GList *get_toplevels (void);
-
-G_END_DECLS
-
-#endif /* __GDK_SURFACE_QUARTZ_H__ */
+++ /dev/null
-/* gdkutils-quartz.c
- *
- * Copyright (C) 2005 Imendio AB
- * Copyright (C) 2010 Kristian Rietveld <kris@gtk.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-
-#include <AppKit/AppKit.h>
-
-#include <gdkquartzutils.h>
-#include "gdkprivate-quartz.h"
-
-NSImage *
-gdk_quartz_pixbuf_to_ns_image_libgtk_only (GdkPixbuf *pixbuf)
-{
- NSBitmapImageRep *bitmap_rep;
- NSImage *image;
- gboolean has_alpha;
-
- has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
-
- /* Create a bitmap image rep */
- bitmap_rep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
- pixelsWide:gdk_pixbuf_get_width (pixbuf)
- pixelsHigh:gdk_pixbuf_get_height (pixbuf)
- bitsPerSample:8 samplesPerPixel:has_alpha ? 4 : 3
- hasAlpha:has_alpha isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace
- bytesPerRow:0 bitsPerPixel:0];
-
- {
- /* Add pixel data to bitmap rep */
- guchar *src, *dst;
- int src_stride, dst_stride;
- int x, y;
-
- src_stride = gdk_pixbuf_get_rowstride (pixbuf);
- dst_stride = [bitmap_rep bytesPerRow];
-
- for (y = 0; y < gdk_pixbuf_get_height (pixbuf); y++)
- {
- src = gdk_pixbuf_get_pixels (pixbuf) + y * src_stride;
- dst = [bitmap_rep bitmapData] + y * dst_stride;
-
- for (x = 0; x < gdk_pixbuf_get_width (pixbuf); x++)
- {
- if (has_alpha)
- {
- guchar red, green, blue, alpha;
-
- red = *src++;
- green = *src++;
- blue = *src++;
- alpha = *src++;
-
- *dst++ = (red * alpha) / 255;
- *dst++ = (green * alpha) / 255;
- *dst++ = (blue * alpha) / 255;
- *dst++ = alpha;
- }
- else
- {
- *dst++ = *src++;
- *dst++ = *src++;
- *dst++ = *src++;
- }
- }
- }
- }
-
- image = [[NSImage alloc] init];
- [image addRepresentation:bitmap_rep];
- [bitmap_rep release];
- [image autorelease];
-
- return image;
-}
-
-NSEvent *
-gdk_quartz_event_get_nsevent (GdkEvent *event)
-{
- /* FIXME: If the event here is unallocated, we crash. */
- return ((GdkEventPrivate *) event)->windowing_data;
-}
-
-/*
- * Code for key code conversion
- *
- * Copyright (C) 2009 Paul Davis
- */
-gunichar
-gdk_quartz_get_key_equivalent (guint key)
-{
- if (key >= GDK_KEY_A && key <= GDK_KEY_Z)
- return key + (GDK_KEY_a - GDK_KEY_A);
-
- if (key >= GDK_KEY_space && key <= GDK_KEY_asciitilde)
- return key;
-
- switch (key)
- {
- case GDK_KEY_BackSpace:
- return NSBackspaceCharacter;
- case GDK_KEY_Delete:
- return NSDeleteFunctionKey;
- case GDK_KEY_Pause:
- return NSPauseFunctionKey;
- case GDK_KEY_Scroll_Lock:
- return NSScrollLockFunctionKey;
- case GDK_KEY_Sys_Req:
- return NSSysReqFunctionKey;
- case GDK_KEY_Home:
- return NSHomeFunctionKey;
- case GDK_KEY_Left:
- case GDK_KEY_leftarrow:
- return NSLeftArrowFunctionKey;
- case GDK_KEY_Up:
- case GDK_KEY_uparrow:
- return NSUpArrowFunctionKey;
- case GDK_KEY_Right:
- case GDK_KEY_rightarrow:
- return NSRightArrowFunctionKey;
- case GDK_KEY_Down:
- case GDK_KEY_downarrow:
- return NSDownArrowFunctionKey;
- case GDK_KEY_Page_Up:
- return NSPageUpFunctionKey;
- case GDK_KEY_Page_Down:
- return NSPageDownFunctionKey;
- case GDK_KEY_End:
- return NSEndFunctionKey;
- case GDK_KEY_Begin:
- return NSBeginFunctionKey;
- case GDK_KEY_Select:
- return NSSelectFunctionKey;
- case GDK_KEY_Print:
- return NSPrintFunctionKey;
- case GDK_KEY_Execute:
- return NSExecuteFunctionKey;
- case GDK_KEY_Insert:
- return NSInsertFunctionKey;
- case GDK_KEY_Undo:
- return NSUndoFunctionKey;
- case GDK_KEY_Redo:
- return NSRedoFunctionKey;
- case GDK_KEY_Menu:
- return NSMenuFunctionKey;
- case GDK_KEY_Find:
- return NSFindFunctionKey;
- case GDK_KEY_Help:
- return NSHelpFunctionKey;
- case GDK_KEY_Break:
- return NSBreakFunctionKey;
- case GDK_KEY_Mode_switch:
- return NSModeSwitchFunctionKey;
- case GDK_KEY_F1:
- return NSF1FunctionKey;
- case GDK_KEY_F2:
- return NSF2FunctionKey;
- case GDK_KEY_F3:
- return NSF3FunctionKey;
- case GDK_KEY_F4:
- return NSF4FunctionKey;
- case GDK_KEY_F5:
- return NSF5FunctionKey;
- case GDK_KEY_F6:
- return NSF6FunctionKey;
- case GDK_KEY_F7:
- return NSF7FunctionKey;
- case GDK_KEY_F8:
- return NSF8FunctionKey;
- case GDK_KEY_F9:
- return NSF9FunctionKey;
- case GDK_KEY_F10:
- return NSF10FunctionKey;
- case GDK_KEY_F11:
- return NSF11FunctionKey;
- case GDK_KEY_F12:
- return NSF12FunctionKey;
- case GDK_KEY_F13:
- return NSF13FunctionKey;
- case GDK_KEY_F14:
- return NSF14FunctionKey;
- case GDK_KEY_F15:
- return NSF15FunctionKey;
- case GDK_KEY_F16:
- return NSF16FunctionKey;
- case GDK_KEY_F17:
- return NSF17FunctionKey;
- case GDK_KEY_F18:
- return NSF18FunctionKey;
- case GDK_KEY_F19:
- return NSF19FunctionKey;
- case GDK_KEY_F20:
- return NSF20FunctionKey;
- case GDK_KEY_F21:
- return NSF21FunctionKey;
- case GDK_KEY_F22:
- return NSF22FunctionKey;
- case GDK_KEY_F23:
- return NSF23FunctionKey;
- case GDK_KEY_F24:
- return NSF24FunctionKey;
- case GDK_KEY_F25:
- return NSF25FunctionKey;
- case GDK_KEY_F26:
- return NSF26FunctionKey;
- case GDK_KEY_F27:
- return NSF27FunctionKey;
- case GDK_KEY_F28:
- return NSF28FunctionKey;
- case GDK_KEY_F29:
- return NSF29FunctionKey;
- case GDK_KEY_F30:
- return NSF30FunctionKey;
- case GDK_KEY_F31:
- return NSF31FunctionKey;
- case GDK_KEY_F32:
- return NSF32FunctionKey;
- case GDK_KEY_F33:
- return NSF33FunctionKey;
- case GDK_KEY_F34:
- return NSF34FunctionKey;
- case GDK_KEY_F35:
- return NSF35FunctionKey;
- default:
- break;
- }
-
- return '\0';
-}
+++ /dev/null
-# FIXME: do we need to do an add_language() for objective-c here?
-gdk_quartz_sources = files([
- 'GdkQuartzView.c',
- 'GdkQuartzNSWindow.c',
- 'gdkcairocontext-quartz.c',
- 'gdkcursor-quartz.c',
- 'gdkdevice-core-quartz.c',
- 'gdkdevicemanager-core-quartz.c',
- 'gdkdisplay-quartz.c',
- 'gdkdisplaymanager-quartz.c',
- 'gdkdnd-quartz.c',
- 'gdkevents-quartz.c',
- 'gdkeventloop-quartz.c',
- 'gdkglcontext-quartz.c',
- 'gdkglobals-quartz.c',
- 'gdkkeys-quartz.c',
- 'gdkscreen-quartz.c',
- 'gdkselection-quartz.c',
- 'gdkutils-quartz.c',
- 'gdksurface-quartz.c',
-])
-
-gdk_quartz_public_headers = files([
- 'gdkquartzcursor.h',
- 'gdkquartzdevice-core.h',
- 'gdkquartzdevicemanager-core.h',
- 'gdkquartzdisplay.h',
- 'gdkquartzdisplaymanager.h',
- 'gdkquartzdnd.h',
- 'gdkquartzkeys.h',
- 'gdkquartzscreen.h',
- 'gdkquartzutils.h',
- 'gdkquartzsurface.h',
-])
-
-install_headers(gdk_quartz_public_headers, 'gdkquartz.h', subdir: 'gtk-4.0/gdk/quartz/')
-
-gdk_quartz_deps = [ # FIXME
-]
-
-libgdk_quartz = static_library('gdk-quartz',
- gdk_quartz_sources, gdkconfig, gdkenum_h,
- include_directories: [confinc, gdkinc],
- c_args: ['-DGTK_COMPILATION', '-DG_LOG_DOMAIN="Gdk"', '-xobjective-c'],
- dependencies: [gdk_deps, gdk_quartz_deps])
+++ /dev/null
-static const struct { gint width, height; gint hotx, hoty; const guchar *bits; } xcursors[] = {
-{ 14, 14, 6, 6, (guchar *) "\x07\xb8\x0f\x3c\x1f\x3e\x3e\x1f\xfc\x0f\xf8\x07\xf0\x03\xf0\x03\xf8\x07\xfc\x0f\x3e\x1f\x1f\x3e\x0f\x3c\x07\x38" },
-{ 16, 16, 7, 7, (guchar *) "\x0f\xf0\x1f\xf8\x3f\xfc\x7f\xfe\xfe\x7f\xfc\x3f\xf8\x1f\xf0\x0f\xf0\x0f\xf8\x1f\xfc\x3f\xfe\x7f\x7f\xfe\x3f\xfc\x1f\xf8\x0f\xf0" },
-{ 14, 14, 13, 0, (guchar *) "\x00\xb0\x00\x3c\x00\x1f\xc0\x1f\xf0\x0f\xfc\x0f\xc0\x07\xe0\x07\x70\x03\x38\x03\x1c\x01\x0e\x01\x07\x00\x02\x00" },
-{ 16, 16, 14, 1, (guchar *) "\x00\xe0\x00\xf8\x00\xfe\x80\x7f\xe0\x7f\xf8\x3f\xfc\x3f\xfc\x1f\xe0\x1f\xf0\x0f\xf8\x0f\x7c\x07\x3e\x07\x1f\x02\x0e\x00\x04\x00" },
-{ 8, 10, 3, 9, (guchar *) "\xff\x00\xff\x18\x18\x18\x18\x5a\x3c\x18" },
-{ 10, 12, 4, 10, (guchar *) "\xff\x23\xff\x03\xff\x03\xff\x03\xff\x03\x78\x00\x78\x00\xfe\x01\xfe\x01\xfe\x01\xfc\x00\x78\x00" },
-{ 8, 10, 3, 9, (guchar *) "\x18\x3c\x5a\x18\x18\x18\x18\xff\x00\xff" },
-{ 10, 12, 4, 10, (guchar *) "\x30\x20\x78\x00\xfe\x01\xfe\x01\xfe\x01\x78\x00\x78\x00\xff\x03\xff\x03\xff\x03\xff\x03\xff\x03" },
-{ 16, 8, 14, 3, (guchar *) "\x80\x00\xe0\x03\x11\x06\xff\xff\x00\x18\x00\x04\x00\x02\xff\x03" },
-{ 16, 9, 14, 4, (guchar *) "\xe0\x00\xf0\x03\xf9\x07\xff\xff\xff\xff\xff\xff\xff\x1f\xff\x07\xff\x03" },
-{ 13, 14, 6, 6, (guchar *) "\x47\x9c\x44\x04\x44\x04\x44\x04\xff\x1f\x45\x14\x45\x14\x45\x14\x45\x14\xff\x1f\x44\x04\x44\x04\x44\x04\x47\x1c" },
-{ 15, 16, 7, 7, (guchar *) "\xdf\x7d\xdf\x7d\xdf\x7d\xdc\x1d\xff\x7f\xff\x7f\xff\x7f\xdf\x7d\xdf\x7d\xff\x7f\xff\x7f\xff\x7f\xdc\x1d\xdf\x7d\xdf\x7d\xdf\x7d" },
-{ 14, 14, 0, 13, (guchar *) "\x03\x80\x03\x00\x23\x08\x23\x04\x23\x02\x23\x01\xa3\x00\x63\x00\xe3\x0f\x03\x00\x03\x00\x03\x00\xff\x3f\xff\x3f" },
-{ 16, 16, 1, 14, (guchar *) "\x0f\x00\x0f\x00\xef\x30\xef\x38\xef\x1c\xef\x0e\xef\x07\xef\x03\xef\x3f\xef\x3f\xef\x3f\x0f\x00\xff\xff\xff\xff\xff\xff\xff\xff" },
-{ 14, 14, 13, 13, (guchar *) "\x00\xb0\x00\x30\x04\x31\x08\x31\x10\x31\x20\x31\x40\x31\x80\x31\xfc\x31\x00\x30\x00\x30\x00\x30\xff\x3f\xff\x3f" },
-{ 16, 16, 14, 14, (guchar *) "\x00\xf0\x00\xf0\x0c\xf7\x1c\xf7\x38\xf7\x70\xf7\xe0\xf7\xc0\xf7\xfc\xf7\xfc\xf7\xfc\xf7\x00\xf0\xff\xff\xff\xff\xff\xff\xff\xff" },
-{ 13, 14, 6, 13, (guchar *) "\x40\x80\x40\x00\x40\x00\x40\x00\x40\x00\x40\x00\x44\x04\x48\x02\x50\x01\xe0\x00\x40\x00\x00\x00\xff\x1f\xff\x1f" },
-{ 15, 16, 7, 14, (guchar *) "\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xcc\x19\xdc\x1d\xf8\x0f\xf0\x07\xe0\x03\xc0\x01\xff\x7f\xff\x7f\xff\x7f\xff\x7f" },
-{ 14, 10, 7, 9, (guchar *) "\xc0\x80\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xff\x3f\xff\x3f" },
-{ 16, 12, 8, 10, (guchar *) "\xc0\x03\xc0\x03\xc0\x03\xc0\x03\xc0\x03\xc0\x03\xc0\x03\xc0\x03\xff\xff\xff\xff\xff\xff\xff\xff" },
-{ 15, 16, 8, 8, (guchar *) "\xff\xff\x01\x00\xfd\x7f\x05\x40\xf5\x5f\x15\x50\xd5\x57\x55\x54\x55\x55\xd5\x55\x15\x54\xf5\x57\x05\x50\xfd\x5f\x01\x40\xff\x7f" },
-{ 16, 16, 8, 8, (guchar *) "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" },
-{ 10, 14, 4, 0, (guchar *) "\x30\x90\x30\x00\x78\x00\x78\x00\xfc\x00\xfc\x00\xfe\x01\xfe\x01\x33\x03\x31\x02\x30\x00\x30\x00\x30\x00\x30\x00" },
-{ 12, 16, 5, 1, (guchar *) "\xf0\x20\xf0\x00\xf8\x01\xf8\x01\xfc\x03\xfc\x03\xfe\x07\xfe\x07\xff\x0f\xff\x0f\xff\x0f\xf7\x0e\xf0\x00\xf0\x00\xf0\x00\xf0\x00" },
-{ 14, 14, 7, 7, (guchar *) "\xe0\x81\xf8\x07\xfc\x0f\x1e\x1e\x0e\x1c\x07\x38\x07\x38\x07\x38\x07\x38\x0e\x1c\x1e\x1e\xfc\x0f\xf8\x07\xe0\x01" },
-{ 16, 16, 8, 8, (guchar *) "\xe0\x07\xf8\x1f\xfc\x3f\xfe\x7f\xfe\x7f\x3f\xfc\x1f\xf8\x1f\xf8\x1f\xf8\x1f\xf8\x3f\xfc\xfe\x7f\xfe\x7f\xfc\x3f\xf8\x1f\xe0\x07" },
-{ 14, 16, 6, 3, (guchar *) "\xfc\x8f\xe6\x19\x13\x33\xc9\x24\x79\x24\x11\x22\xe3\x31\xfe\x1f\xca\x14\xca\x14\xca\x14\xea\x15\xcb\x34\x0f\x3c\xff\x3f\xff\x3f" },
-{ 15, 16, 6, 3, (guchar *) "\xfe\x1f\xf7\x39\xdb\x77\xed\x6d\xfd\x6f\xf9\x66\xf3\x73\xff\x3f\xeb\x35\xeb\x35\xeb\x35\xfb\x37\xeb\x75\xcf\x7c\xff\x7f\xff\x7f" },
-{ 15, 16, 7, 9, (guchar *) "\xf8\x8f\x04\x10\x06\x60\x0a\x58\xf2\x47\x03\x40\x03\x40\x02\x40\x02\x40\x9a\x58\x56\x55\xd7\x55\x5b\x59\x02\x40\x02\x40\xfc\x3f" },
-{ 16, 16, 7, 9, (guchar *) "\xf8\x0f\xfc\x1f\xfe\xff\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xfc\x3f" },
-{ 16, 15, 7, 7, (guchar *) "\x40\x01\x40\x01\x40\x01\x40\x01\x40\x01\x40\x01\x7f\xff\x00\x00\x7f\xff\x40\x01\x40\x01\x40\x01\x40\x01\x40\x01\x40\x01" },
-{ 16, 16, 7, 7, (guchar *) "\xe0\x03\xe0\x03\xe0\x03\xe0\x03\xe0\x03\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x03\xe0\x03\xe0\x03\xe0\x03\xe0\x03\xe0\x03" },
-{ 16, 15, 7, 7, (guchar *) "\x42\x21\x45\x51\x4a\x29\x54\x15\x68\x0b\x50\x05\xbf\xfe\x40\x01\xbf\xfe\x50\x05\x68\x0b\x54\x15\x4a\x29\x45\x51\x42\x21" },
-{ 16, 15, 7, 7, (guchar *) "\x66\x33\x6d\xdb\x7b\x6f\x76\x37\x6c\x1b\x5f\xfd\x3f\xfe\x80\x00\x3f\xfe\x5f\xfd\x6c\x1b\x76\x37\x7b\x6f\x6d\xdb\x66\x33" },
-{ 16, 15, 7, 7, (guchar *) "\x80\x00\x80\x00\x80\x00\x80\x00\x80\x00\x80\x00\x80\x00\x7f\xff\x80\x00\x80\x00\x80\x00\x80\x00\x80\x00\x80\x00\x80\x00" },
-{ 16, 16, 7, 7, (guchar *) "\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xff\xff\xff\xff\xff\xff\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01" },
-{ 15, 15, 7, 7, (guchar *) "\x40\x81\x60\x03\x50\x05\x48\x09\x44\x11\x42\x21\x7f\x7f\x00\x00\x7f\x7f\x42\x21\x44\x11\x48\x09\x50\x05\x60\x03\x40\x01" },
-{ 16, 16, 7, 7, (guchar *) "\xe0\x03\xf0\x07\xf8\x0f\xdc\x1d\xce\x39\xc7\x71\xff\xff\x7f\xff\xff\xff\xc7\x71\xce\x39\xdc\x1d\xf8\x0f\xf0\x07\xe0\x03\xc0\x01" },
-{ 10, 10, 5, 5, (guchar *) "\x78\x90\xfe\x01\xfe\x01\xff\x03\xff\x03\xff\x03\xff\x03\xfe\x01\xfe\x01\x78\x00" },
-{ 12, 12, 6, 6, (guchar *) "\xf8\x21\xfe\x07\xfe\x07\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xfe\x07\xfe\x07\xf8\x01" },
-{ 12, 12, 6, 5, (guchar *) "\xff\x9f\x01\x08\x01\x08\x01\x08\x01\x08\x61\x08\x61\x08\x01\x08\x01\x08\x01\x08\x01\x08\xff\x0f" },
-{ 14, 14, 7, 6, (guchar *) "\xff\x3f\xff\x3f\xff\x3f\x07\x38\x07\x38\xe7\x39\xe7\x39\xe7\x39\xe7\x39\x07\x38\x07\x38\xff\x3f\xff\x3f\xff\x3f" },
-{ 10, 14, 5, 7, (guchar *) "\x30\x90\x78\x00\xfc\x00\xb6\x01\x33\x03\x30\x00\x30\x00\x30\x00\x30\x00\x33\x03\xb6\x01\xfc\x00\x78\x00\x30\x00" },
-{ 12, 16, 6, 8, (guchar *) "\xf0\x20\xf8\x01\xfc\x03\xfe\x07\xff\x0f\xff\x0f\xff\x0f\xf0\x00\xf0\x00\xff\x0f\xff\x0f\xff\x0f\xfe\x07\xfc\x03\xf8\x01\xf0\x00" },
-{ 15, 15, 14, 0, (guchar *) "\x00\xc0\x00\x30\x00\x3c\x00\x1f\xc0\x1f\xf0\x0f\xfc\x0f\x80\x07\x40\x07\x20\x03\x10\x03\x08\x01\x04\x01\x02\x00\x01\x00" },
-{ 15, 16, 14, 0, (guchar *) "\x00\x60\x00\x78\x00\x7e\x80\x3f\xe0\x1f\xf8\x1f\xfe\x0f\xfe\x0f\xe0\x07\xf0\x07\xb8\x03\x9c\x03\x8e\x01\x87\x01\x03\x00\x01\x00" },
-{ 15, 15, 14, 0, (guchar *) "\x00\x40\x00\x30\x00\x3c\x00\x1f\xc0\x1f\x00\x0e\x00\x0d\x80\x04\x40\x04\x20\x00\x10\x00\x08\x00\x04\x00\x02\x00\x01\x00" },
-{ 15, 15, 14, 0, (guchar *) "\x00\x60\x00\x78\x00\x3e\x80\x3f\xe0\x1f\xe0\x1f\x80\x0f\xc0\x0f\xe0\x06\x70\x02\x38\x00\x1c\x00\x0e\x00\x07\x00\x03\x00" },
-{ 12, 12, 6, 5, (guchar *) "\xff\x1f\x91\x08\x99\x09\x0d\x0b\x07\x0e\x61\x08\x61\x08\x07\x0e\x0d\x0b\x99\x09\x91\x08\xff\x0f" },
-{ 14, 14, 7, 6, (guchar *) "\xff\x3f\xff\x3f\xf3\x33\xfb\x37\x3f\x3f\xdf\x3e\xef\x3d\xef\x3d\xdf\x3e\x3f\x3f\xfb\x37\xf3\x33\xff\x3f\xff\x3f" },
-{ 14, 14, 6, 6, (guchar *) "\xf1\x03\xfb\x07\x1f\x0c\x09\x08\x19\x00\x3f\x00\x00\x00\x00\x00\x00\x3f\x00\x26\x04\x24\x0c\x3e\xf8\x37\xf0\x23" },
-{ 16, 16, 7, 7, (guchar *) "\xe3\x07\xf7\x0f\xff\x1f\xff\x3f\x3f\x38\xff\x30\xff\x00\xff\x00\x00\xff\x00\xff\x0c\xfe\x1c\xfc\xfc\xff\xf8\xff\xf0\xef\xe0\xc7" },
-{ 14, 14, 7, 7, (guchar *) "\xc0\x00\xe0\x01\xf0\x03\xc0\x00\xc4\x08\xc6\x18\xff\x3f\xff\x3f\xc6\x18\xc4\x08\xc0\x00\xf0\x03\xe0\x01\xc0\x00" },
-{ 16, 16, 8, 8, (guchar *) "\xc0\x03\xc0\x07\xe0\x07\xf0\x0f\xe8\x17\xdc\x3b\xff\xff\xff\xff\xff\xff\xff\xff\xdc\x3b\xe8\x17\xf0\x0f\xe0\x07\xc0\x03\xc0\x03" },
-{ 16, 15, 14, 2, (guchar *) "\x00\x1e\x00\x0e\x01\xcc\xf9\x0d\xff\x0f\x7f\x0c\x3f\x0c\x06\x1c\x00\x0f\xf8\x07\x10\x00\x10\x00\x10\x00\x10\x00\x78\x00" },
-{ 16, 16, 14, 3, (guchar *) "\x00\x3f\x00\x3f\x03\xff\xff\xff\xff\xff\xff\x3f\xff\x3f\xff\x3f\xff\x3f\xff\x3f\xfe\x1f\xf8\x0f\x38\x00\x38\x00\xfc\x00\xfc\x00" },
-{ 16, 16, 2, 0, (guchar *) "\xfc\x00\x08\x01\x13\x02\x57\x05\x13\x04\xd3\x05\x1f\x3c\x1c\xfc\x10\xe4\x10\xe4\x90\xf4\x90\xe4\x90\x04\x88\x08\x84\x10\x7c\x1f" },
-{ 16, 16, 2, 0, (guchar *) "\xfc\x00\xfb\x01\xf7\x03\xff\x07\xf7\x07\xf7\x3f\xff\x7f\xff\xff\xfc\xf7\xf0\xf7\xf0\xff\xf0\xf7\xf0\xe7\xf8\x0f\xfc\x1f\x7c\x1f" },
-{ 13, 16, 12, 0, (guchar *) "\x00\x18\x00\x1e\x80\x07\xc0\x03\xe0\x01\xf0\x03\xf8\x07\xfa\x03\xff\x07\xfd\x07\xf0\x03\xf0\x01\x29\x00\x23\x00\x16\x00\x0c\x00" },
-{ 13, 16, 12, 0, (guchar *) "\x00\xdc\x00\x1f\xc0\x0f\xe0\x07\xf0\x03\xf8\x07\xfe\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x07\xff\x03\xff\x01\x7f\x00\x3f\x00\x1e\x00" },
-{ 15, 14, 0, 0, (guchar *) "\xfe\x01\x01\x02\x7e\x04\x08\x08\x70\x08\x08\x08\x70\x14\x08\x22\x30\x41\xc0\x20\x40\x12\x80\x08\x00\x05\x00\x02" },
-{ 16, 16, 0, 1, (guchar *) "\xfe\x01\xff\x03\xff\x07\xff\x0f\xfe\x1f\xf8\x1f\xfc\x1f\xf8\x3f\xfc\x7f\xf8\xff\xf0\x7f\xe0\x3f\xc0\x1f\x80\x0f\x00\x07\x00\x02" },
-{ 15, 14, 6, 8, (guchar *) "\x7c\x1f\xc6\x31\x83\x60\x01\x40\x01\x40\x01\x40\x01\x40\x03\x60\x06\x30\x0c\x18\x18\x0c\x30\x06\x60\x03\xc0\x01" },
-{ 15, 14, 6, 8, (guchar *) "\x7c\x9f\xfe\x3f\xc7\x71\x83\x60\x03\x60\x03\x60\x43\x61\x87\x70\x0e\x38\x1c\x1c\x38\x0e\xf0\x07\xe0\x03\xc0\x01" },
-{ 16, 16, 8, 8, (guchar *) "\xff\xff\xab\xaa\x55\xd5\xab\xaa\x05\xd0\x0b\xa0\x05\xd0\x0b\xa0\x05\xd0\x0b\xa0\x05\xd0\x0b\xa0\x55\xd5\xab\xaa\x55\xd5\xff\xff" },
-{ 16, 16, 8, 8, (guchar *) "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" },
-{ 14, 14, 7, 6, (guchar *) "\xfe\x1f\xfc\x0f\xf9\x27\xf3\x33\xe7\x39\xcf\x3c\xff\x3f\xff\x3f\xcf\x3c\xe7\x39\xf3\x33\xf9\x27\xfc\x0f\xfe\x1f" },
-{ 16, 16, 8, 7, (guchar *) "\xfc\x3f\xfe\x7f\xfe\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\x7f\xfe\x7f\xfc\x3f" },
-{ 8, 14, 0, 0, (guchar *) "\x01\x03\x07\x0f\x1f\x3f\x7f\xff\x1f\x1b\x31\x30\x60\x60" },
-{ 10, 16, 1, 1, (guchar *) "\x03\xc0\x07\x00\x0f\x00\x1f\x00\x3f\x00\x7f\x00\xff\x00\xff\x01\xff\x03\xff\x03\x7f\x00\xf7\x00\xf3\x00\xe0\x01\xe0\x01\xc0\x00" },
-{ 14, 13, 0, 6, (guchar *) "\x03\x00\x03\x00\x83\x00\x43\x00\x23\x00\x13\x00\xfb\x3f\x13\x00\x23\x00\x43\x00\x83\x00\x03\x00\x03\x00" },
-{ 16, 15, 1, 7, (guchar *) "\x0f\x00\x0f\x00\x0f\x03\x8f\x03\xcf\x01\xef\x00\xff\xff\xff\xff\xff\xff\xef\x00\xcf\x01\x8f\x03\x0f\x03\x0f\x00\x0f\x00" },
-{ 10, 14, 0, 7, (guchar *) "\x03\x10\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\xff\x03\xff\x03\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00" },
-{ 12, 16, 1, 8, (guchar *) "\x0f\xc0\x0f\x00\x0f\x00\x0f\x00\x0f\x00\x0f\x00\xff\x0f\xff\x0f\xff\x0f\xff\x0f\x0f\x00\x0f\x00\x0f\x00\x0f\x00\x0f\x00\x0f\x00" },
-{ 16, 16, 8, 8, (guchar *) "\x01\xc0\xfe\xbf\xfe\xbf\x22\xa2\xa2\xaa\xa2\xaa\xa2\xaa\xa2\xaa\x22\xa2\xfe\xbf\xfe\xbf\xfe\xbf\xfe\xbf\xfe\xbf\xfe\xbf\x01\xc0" },
-{ 15, 16, 8, 8, (guchar *) "\xfe\xbf\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xfe\x3f" },
-{ 10, 10, 0, 9, (guchar *) "\x03\x10\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\xff\x03\xff\x03" },
-{ 12, 12, 1, 10, (guchar *) "\x0f\xc0\x0f\x00\x0f\x00\x0f\x00\x0f\x00\x0f\x00\x0f\x00\x0f\x00\xff\x0f\xff\x0f\xff\x0f\xff\x0f" },
-{ 10, 10, 9, 9, (guchar *) "\x00\x13\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03\xff\x03\xff\x03" },
-{ 12, 12, 10, 10, (guchar *) "\x00\xcf\x00\x0f\x00\x0f\x00\x0f\x00\x0f\x00\x0f\x00\x0f\x00\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f" },
-{ 16, 16, 14, 5, (guchar *) "\xc0\x01\x78\x0f\x40\x01\x81\x00\xc2\xe1\x24\xd2\xb8\x0e\xa0\x02\x20\x02\x40\x01\x20\x02\x90\x04\x48\x09\x28\x0a\x1e\x3c\x1f\xfc" },
-{ 16, 16, 14, 5, (guchar *) "\xf8\x07\xfc\x0f\xfc\x1f\xc3\x41\xe7\xe3\xfe\xff\xfc\xdf\xf8\x0f\xe0\x07\xe0\x03\xf0\x07\xf8\x0f\xfc\x1f\x7e\x3f\x3f\xfe\x3f\xfe" },
-{ 16, 16, 8, 8, (guchar *) "\x01\xc0\xfe\xbf\xfe\xbf\x22\xa2\x2a\xaa\x2a\xaa\x2a\xaa\x2a\xaa\x22\xa2\xfe\xbf\xfe\xbf\xfe\xbf\xfe\xbf\xfe\xbf\xfe\xbf\x01\xc0" },
-{ 15, 16, 8, 8, (guchar *) "\xfe\xbf\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xfe\x3f" },
-{ 15, 14, 4, 1, (guchar *) "\xe0\x00\x30\x00\x60\x00\xc0\x00\xfe\x1f\x01\x20\xcd\x6c\xcd\x6c\xcd\x6c\x01\x60\x01\x60\x06\x38\x18\x06\xe0\x01" },
-{ 16, 16, 4, 1, (guchar *) "\xf0\x01\x78\x00\xf0\x00\xe0\x00\xfe\x1f\xff\x3f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfc\xef\xf8\x07\xf0\x03\xe0\x01" },
-{ 11, 16, 10, 15, (guchar *) "\x0e\x10\x11\x00\x31\x00\x52\x00\x5e\x00\x84\x00\x88\x00\x08\x01\x10\x01\x30\x02\x20\x02\x40\x04\x80\x07\x00\x07\x00\x06\x00\x04" },
-{ 13, 16, 11, 15, (guchar *) "\x3f\xc0\x7f\x00\xff\x00\xfe\x00\xfc\x01\xfc\x01\xf8\x03\xf0\x03\xf0\x07\xe0\x07\xe0\x0f\xc0\x1f\x80\x1f\x00\x1f\x00\x1e\x00\x1c" },
-{ 15, 16, 7, 12, (guchar *) "\xe0\x01\xf0\x03\xf8\x07\xcc\x0c\xcc\x0c\xf8\x07\xf0\x03\xe0\x01\xe1\x21\xe1\x61\xc2\x10\x1c\x0e\xe0\x01\xf8\x47\x0f\x7c\x01\x20" },
-{ 16, 16, 7, 12, (guchar *) "\xf0\x03\xf8\x07\xfc\x0f\xfe\x1f\xfe\x1f\xfc\x0f\xf8\x07\xf1\x83\xf1\xe3\xf3\xf3\xef\x39\x1e\x1e\xe0\x01\xfe\xc7\xff\xff\x0f\x7c" },
-{ 10, 10, 4, 5, (guchar *) "\x30\x10\x30\x00\x30\x00\x30\x00\xff\x03\xff\x03\x30\x00\x30\x00\x30\x00\x30\x00" },
-{ 12, 12, 5, 6, (guchar *) "\xf0\xc0\xf0\x00\xf0\x00\xf0\x00\xff\x0f\xff\x0f\xff\x0f\xff\x0f\xf0\x00\xf0\x00\xf0\x00\xf0\x00" },
-{ 9, 15, 4, 7, (guchar *) "\x7c\x10\xfe\x00\xc7\x01\x83\x01\x87\x01\xc6\x01\xe0\x00\x78\x00\x38\x00\x28\x00\x28\x00\xee\x00\x6c\x00\x38\x00\x10\x00" },
-{ 11, 16, 5, 8, (guchar *) "\xf8\xc0\xfc\x01\xfe\x03\xff\x07\x8f\x07\x9f\x07\xde\x07\xfc\x03\xf8\x01\xf8\x00\xf8\x00\xfc\x01\xfe\x03\xfc\x01\xf8\x00\x70\x00" },
-{ 8, 14, 7, 0, (guchar *) "\x80\xc0\xe0\xf0\xf8\xfc\xfe\xff\xf8\xd8\x8c\x0c\x06\x06" },
-{ 10, 16, 8, 1, (guchar *) "\x00\xc3\x80\x03\xc0\x03\xe0\x03\xf0\x03\xf8\x03\xfc\x03\xfe\x03\xff\x03\xff\x03\xf8\x03\xbc\x03\x3c\x03\x1e\x00\x1e\x00\x0c\x00" },
-{ 14, 13, 13, 6, (guchar *) "\x00\x30\x00\x30\x40\x30\x80\x30\x00\x31\x00\x32\xff\x37\x00\x32\x00\x31\x80\x30\x40\x30\x00\x30\x00\x30" },
-{ 16, 15, 14, 7, (guchar *) "\x00\xf0\x00\xf0\xc0\xf0\xc0\xf1\x80\xf3\x00\xf7\xff\xff\xff\xff\xff\xff\x00\xf7\x80\xf3\xc0\xf1\xc0\xf0\x00\xf0\x00\xf0" },
-{ 10, 14, 9, 7, (guchar *) "\x00\x13\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03\xff\x03\xff\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03" },
-{ 12, 16, 10, 8, (guchar *) "\x00\xcf\x00\x0f\x00\x0f\x00\x0f\x00\x0f\x00\x0f\xff\x0f\xff\x0f\xff\x0f\xff\x0f\x00\x0f\x00\x0f\x00\x0f\x00\x0f\x00\x0f\x00\x0f" },
-{ 16, 16, 8, 8, (guchar *) "\x01\xc0\xfe\xbf\xfe\xbf\x22\xa2\xaa\xa2\xaa\xa2\xaa\xa2\xaa\xa2\x22\xa2\xfe\xbf\xfe\xbf\xfe\xbf\xfe\xbf\xfe\xbf\xfe\xbf\x01\xc0" },
-{ 15, 16, 8, 8, (guchar *) "\xfe\xbf\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xfe\x3f" },
-{ 14, 14, 6, 6, (guchar *) "\xff\x3f\x01\x22\x01\x22\x01\x22\xff\x23\x11\x22\x11\x22\x11\x22\x11\x22\xf1\x3f\x11\x20\x11\x20\x11\x20\xff\x3f" },
-{ 16, 16, 7, 7, (guchar *) "\xff\xff\xff\xff\xff\xff\x07\xee\xff\xef\xff\xef\xff\xef\x77\xee\x77\xee\xf7\xff\xf7\xff\xf7\xff\x77\xe0\xff\xff\xff\xff\xff\xff" },
-{ 12, 13, 6, -1, (guchar *) "\x80\x10\x80\x00\xa0\x01\xa0\x01\xb0\x01\xb0\x03\xb8\x03\xb8\x03\xbc\x07\xbc\x07\xbe\x07\xbe\x0f\x1f\x07" },
-{ 16, 16, 8, 0, (guchar *) "\x00\x03\x00\x07\x80\x07\xc0\x0f\xc0\x0f\xe0\x0f\xe0\x1f\xf0\x1f\xf0\x1f\xf8\x3f\xf8\x3f\xfc\x3f\xfc\xff\xfe\xff\xff\x1f\xfe\x07" },
-{ 7, 15, 3, 15, (guchar *) "\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x7f\x3e\x1c\x08" },
-{ 9, 16, 4, 15, (guchar *) "\x7c\xc0\x7c\x00\x7c\x00\x7c\x00\x7c\x00\x7c\x00\x7c\x00\x7c\x00\x7c\x00\x7c\x00\xff\x01\xff\x01\xfe\x00\x7c\x00\x38\x00\x10\x00" },
-{ 15, 7, 7, 3, (guchar *) "\x08\x08\x0c\x18\xfe\x3f\x0f\x78\xfe\x3f\x0c\x18\x08\x08" },
-{ 15, 9, 7, 4, (guchar *) "\x18\x8c\x1c\x1c\xfe\x3f\xff\x7f\xff\x7f\xff\x7f\xfe\x3f\x1c\x1c\x18\x0c" },
-{ 15, 7, -1, 3, (guchar *) "\x08\x00\x0c\x00\xfe\x7f\x0f\x00\xfe\x7f\x0c\x00\x08\x00" },
-{ 16, 9, 0, 4, (guchar *) "\x30\x00\x38\x00\xfc\xff\xfe\xff\xff\xff\xfe\xff\xfc\xff\x38\x00\x30\x00" },
-{ 15, 7, 15, 3, (guchar *) "\x00\x08\x00\x18\xff\x3f\x00\x78\xff\x3f\x00\x18\x00\x08" },
-{ 16, 9, 15, 4, (guchar *) "\x00\x0c\x00\x1c\xff\x3f\xff\x7f\xff\xff\xff\x7f\xff\x3f\x00\x1c\x00\x0c" },
-{ 7, 15, 3, -1, (guchar *) "\x08\x9c\x3e\x7f\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14" },
-{ 9, 16, 4, 0, (guchar *) "\x10\xc0\x38\x00\x7c\x00\xfe\x00\xff\x01\xff\x01\x7c\x00\x7c\x00\x7c\x00\x7c\x00\x7c\x00\x7c\x00\x7c\x00\x7c\x00\x7c\x00\x7c\x00" },
-{ 7, 15, 3, 7, (guchar *) "\x08\x9c\x3e\x7f\x14\x14\x14\x14\x14\x14\x14\x7f\x3e\x1c\x08" },
-{ 9, 15, 4, 7, (guchar *) "\x38\xc0\x7c\x00\xfe\x00\xff\x01\xff\x01\x7c\x00\x7c\x00\x7c\x00\x7c\x00\x7c\x00\xff\x01\xff\x01\xfe\x00\x7c\x00\x38\x00" },
-{ 15, 16, 10, 0, (guchar *) "\x00\x84\x00\x0e\x00\x1f\x80\x7b\xa0\x7b\x90\x7b\x88\x7b\x88\x7b\x88\x7b\x88\x7b\x8c\x7b\x8e\x7b\xbf\x7b\x18\x11\x00\x1e\x00\x0c" },
-{ 16, 16, 11, 0, (guchar *) "\x00\x1c\x00\x3e\x00\x7f\x00\xff\x60\xff\x70\xff\x78\xff\x78\xff\x78\xff\x78\xff\x7c\xff\x7e\xff\x7f\xff\x7e\x7f\x30\x7e\x00\x3c" },
-{ 14, 14, 7, 7, (guchar *) "\xff\xc0\x01\x00\x01\x00\x01\x00\xf1\x03\x11\x02\x11\x22\x11\x22\x10\x22\xf0\x23\x00\x24\x00\x28\x00\x30\xc0\x3f" },
-{ 16, 16, 8, 8, (guchar *) "\xff\x03\xff\x03\xff\x03\x07\x00\xf7\x0f\xf7\x0f\xf7\xef\x77\xee\x77\xee\xf7\xef\xf0\xef\xf0\xff\x00\xf8\xc0\xff\xc0\xff\xc0\xff" },
-{ 16, 16, 6, 7, (guchar *) "\x04\x08\x08\x04\x08\x04\x10\x02\x10\x02\xe1\xe1\xe6\x19\xf8\x07\xf8\x07\xe6\x19\xe1\xe1\x10\x02\x10\x02\x08\x04\x08\x04\x04\x08" },
-{ 16, 16, 6, 7, (guchar *) "\x06\x18\x0c\x0c\x08\x04\x18\x06\xf1\x83\xf3\xf3\xf6\x3b\xfc\x0f\xfc\x07\xf6\x1f\xf3\xf3\xf1\x83\x18\x02\x18\x06\x0c\x0c\x06\x18" },
-{ 11, 16, 9, 2, (guchar *) "\x00\xe6\x80\x00\x2c\x06\x9e\x00\x16\x06\x3f\x00\x21\x00\x27\x00\x25\x00\x27\x00\x25\x00\x27\x00\x27\x00\x21\x00\x21\x00\x3f\x00" },
-{ 12, 16, 10, 2, (guchar *) "\x00\x4c\x18\x0d\x7c\x0d\x7c\x0d\x7e\x0d\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00\xff\x00" },
-{ 15, 16, 7, 7, (guchar *) "\x80\x80\x40\x01\x40\x01\x40\x01\x20\x02\x20\x02\x20\x02\x9c\x1c\x03\x60\x1c\x1c\x90\x04\x48\x09\x24\x12\x14\x14\x0c\x18\x04\x10" },
-{ 16, 16, 7, 7, (guchar *) "\x80\x00\xc0\x01\xc0\x01\x60\x03\x60\x03\x30\x06\x38\x1e\x9f\x7c\x03\xe0\x1f\x7c\x9c\x1c\xcc\x19\x66\x33\x36\x36\x1e\x3c\x0e\x38" },
-{ 15, 13, 7, 6, (guchar *) "\xc0\x81\xf0\x07\x38\x0e\x0c\x18\x06\x30\x83\x60\x43\x61\x83\x60\x06\x30\x0c\x18\x38\x0e\xf0\x07\xc0\x01" },
-{ 16, 14, 7, 7, (guchar *) "\xe0\x03\xf0\x07\xf8\x0f\x3c\x1e\x0e\x38\x87\x70\xc3\xe1\x63\xe3\xc3\xe1\x87\x70\x0e\x38\x3c\x1e\xf8\x0f\xe0\x03" },
-{ 13, 13, 6, 6, (guchar *) "\x40\xe0\x40\x00\x40\x00\x40\x00\x40\x00\x40\x00\xff\x1f\x40\x00\x40\x00\x40\x00\x40\x00\x40\x00\x40\x00" },
-{ 15, 15, 7, 7, (guchar *) "\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xff\x7f\xff\x7f\xff\x7f\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01" },
-{ 14, 14, 0, 0, (guchar *) "\x03\xc0\x0f\x00\x3e\x00\xfe\x00\xfc\x03\xfc\x0f\xf8\x00\xf8\x00\x30\x01\x30\x02\x20\x04\x20\x08\x00\x10\x00\x20" },
-{ 16, 16, 1, 1, (guchar *) "\x07\x00\x1f\x00\x7f\x00\xfe\x01\xfe\x07\xfc\x3f\xfc\x3f\xf8\x3f\xf8\x03\xf0\x07\xf0\x0e\xe0\x1c\xe0\x38\xe0\x70\x00\xe0\x00\xc0" },
-{ 14, 14, 0, 0, (guchar *) "\xff\xff\xff\x3f\x03\x00\x03\x00\x03\x00\xe3\x0f\x63\x00\xa3\x00\x23\x01\x23\x02\x23\x04\x23\x08\x03\x00\x03\x00" },
-{ 16, 16, 1, 1, (guchar *) "\xff\xff\xff\xff\xff\xff\xff\xff\x0f\x00\xef\x3f\xef\x3f\xef\x3f\xef\x03\xef\x07\xef\x0e\xef\x1c\xef\x38\xef\x30\x0f\x00\x0f\x00" },
-{ 14, 14, 13, 0, (guchar *) "\xff\xff\xff\x3f\x00\x30\x00\x30\x00\x30\xfc\x31\x80\x31\x40\x31\x20\x31\x10\x31\x08\x31\x04\x31\x00\x30\x00\x30" },
-{ 16, 16, 14, 1, (guchar *) "\xff\xff\xff\xff\xff\xff\xff\xff\x00\xf0\xfc\xf7\xfc\xf7\xfc\xf7\xc0\xf7\xe0\xf7\x70\xf7\x38\xf7\x1c\xf7\x0c\xf7\x00\xf0\x00\xf0" },
-{ 13, 14, 6, 0, (guchar *) "\xff\xff\xff\x1f\x00\x00\x40\x00\xe0\x00\x50\x01\x48\x02\x44\x04\x40\x00\x40\x00\x40\x00\x40\x00\x40\x00\x40\x00" },
-{ 15, 16, 7, 1, (guchar *) "\xff\x7f\xff\x7f\xff\x7f\xff\x7f\xc0\x01\xe0\x03\xf0\x07\xf8\x0f\xdc\x1d\xcc\x19\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x01" },
-{ 14, 10, 7, 0, (guchar *) "\xff\xff\xff\x3f\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00\xc0\x00" },
-{ 16, 12, 8, 1, (guchar *) "\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x03\xc0\x03\xc0\x03\xc0\x03\xc0\x03\xc0\x03\xc0\x03\xc0\x03" },
-{ 7, 16, 3, 0, (guchar *) "\x88\x80\x1c\x3e\x7f\x77\x7f\x3e\x1c\x08\x5d\x6b\x49\x41\x41\x41" },
-{ 9, 16, 4, 0, (guchar *) "\x38\x40\x38\x00\x7c\x00\xfe\x00\xff\x01\xff\x01\xff\x01\xfe\x00\x7c\x00\xba\x00\xff\x01\xff\x01\xff\x01\xd7\x01\xd7\x01\xc7\x01" },
-{ 10, 10, 0, 0, (guchar *) "\xff\xe3\xff\x03\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00" },
-{ 12, 12, 1, 1, (guchar *) "\xff\x4f\xff\x0f\xff\x0f\xff\x0f\x0f\x00\x0f\x00\x0f\x00\x0f\x00\x0f\x00\x0f\x00\x0f\x00\x0f\x00" },
-{ 14, 14, 7, 2, (guchar *) "\x88\xc4\x20\x0a\xc9\x32\xf2\x09\x4c\x06\x43\x18\x40\x00\x40\x00\x40\x00\x40\x00\x40\x00\x40\x01\x40\x01\x80\x00" },
-{ 16, 16, 8, 2, (guchar *) "\xe8\x76\xfb\xdf\xfd\x3f\xfe\xff\xff\x3f\xff\xff\xcf\x79\xc0\x01\xc0\x01\xc0\x01\xc0\x01\xc0\x07\xc0\x07\xc0\x07\xc0\x07\x80\x03" },
-{ 10, 10, 9, 0, (guchar *) "\xff\xe3\xff\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03" },
-{ 12, 12, 10, 1, (guchar *) "\xff\x4f\xff\x0f\xff\x0f\xff\x0f\x00\x0f\x00\x0f\x00\x0f\x00\x0f\x00\x0f\x00\x0f\x00\x0f\x00\x0f" },
-{ 16, 16, 15, 9, (guchar *) "\xf8\x07\xf8\x07\xf8\x07\xfc\x0f\x86\x18\x83\x30\x81\xe0\xc1\xe1\xc1\xe1\x21\xe0\x13\x30\x06\x18\xfc\x0f\xf8\x07\xf8\x07\xf8\x07" },
-{ 16, 16, 15, 9, (guchar *) "\xfc\x0f\xfc\x0f\xfc\x0f\xfe\x1f\xff\x3f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x3f\xfe\x1f\xfc\x0f\xfc\x0f\xfc\x0f" },
-{ 7, 14, 3, 7, (guchar *) "\xf7\x9c\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x1c\x77" },
-{ 9, 16, 4, 8, (guchar *) "\xef\x41\xff\x01\xff\x01\x7c\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x38\x00\x7c\x00\xff\x01\xff\x01\xef\x01" },
-};
#ifdef GDK_RENDERING_VULKAN
#include "vulkan/gskvulkanrenderer.h"
#endif
+#ifdef GDK_WINDOWING_MACOS
+#include <gdk/macos/gdkmacos.h>
+#endif
typedef struct
{
if (GDK_IS_BROADWAY_SURFACE (surface))
return GSK_TYPE_BROADWAY_RENDERER;
#endif
+#ifdef GDK_WINDOWING_MACOS
+ if (GDK_IS_MACOS_SURFACE (surface))
+ return GSK_TYPE_GL_RENDERER;
+#endif
return G_TYPE_INVALID;
}
x11_enabled = get_option('x11-backend')
wayland_enabled = get_option('wayland-backend')
broadway_enabled = get_option('broadway-backend')
+macos_enabled = get_option('macos-backend')
quartz_enabled = get_option('quartz-backend')
win32_enabled = get_option('win32-backend')
wayland_enabled = false
else
quartz_enabled = false
+ macos_enabled = false
endif
if os_win32
pkg_targets = ''
display_backends = []
-foreach backend: [ 'broadway', 'quartz', 'wayland', 'win32', 'x11', ]
+foreach backend: [ 'broadway', 'quartz', 'macos', 'wayland', 'win32', 'x11', ]
if get_variable('@0@_enabled'.format(backend))
pkgs += ['gtk4-@0@.pc'.format(backend)]
pkg_targets += ' ' + backend
description : 'Enable the Windows gdk backend (only when building on Windows)')
option('quartz-backend', type: 'boolean', value: true,
description : 'Enable the macOS gdk backend (only when building on macOS)')
+option('macos-backend', type: 'boolean', value: true,
+ description : 'Enable the macOS gdk backend (only when building on macOS)')
# Media backends
option('media', type: 'string', value: 'gstreamer',